blob: f41941030fe7ca493679e400620923b809b9b78f [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> {
Patrick Williamsa9423462023-10-20 11:19:36 -050095 if (resp.metadata.size() != 1)
96 {
97 throw ToolException("Invalid stat metadata");
98 }
99 auto result = static_cast<ipmi_flash::ActionStatus>(resp.metadata[0]);
100 switch (result)
101 {
102 case ipmi_flash::ActionStatus::failed:
103 throw ToolException("BMC reported failure");
104 case ipmi_flash::ActionStatus::unknown:
105 case ipmi_flash::ActionStatus::running:
106 return std::nullopt;
107 case ipmi_flash::ActionStatus::success:
108 return true;
109 default:
110 throw ToolException("Unrecognized action status");
111 }
112 });
Patrick Venture01123b22019-06-20 13:49:06 -0700113}
114
Jie Yang328f5202021-03-16 00:52:07 -0700115/* Poll an open blob session for reading.
116 *
117 * The committing bit indicates that the blob is not available for reading now
118 * and the reader might come back and check the state later.
119 *
120 * Polling finishes under the following conditions:
121 * - The open_read bit set -> stat successful
122 * - The open_read and committing bits unset -> stat failed;
123 * - Blob exception was received;
124 * - Time ran out.
125 * Polling continues when the open_read bit unset and committing bit set.
126 * If the blob is not open_read and not committing, then it is an error to the
127 * reader.
128 */
William A. Kennington IIIf88bcf32021-10-14 02:15:10 -0700129uint32_t pollReadReady(std::uint16_t session, ipmiblob::BlobInterface* blob)
Jie Yang328f5202021-03-16 00:52:07 -0700130{
William A. Kennington IIIcf376632021-10-13 21:40:11 -0700131 return pollStat(
132 session, blob,
133 [](const ipmiblob::StatResponse& resp) -> std::optional<uint32_t> {
Patrick Williamsa9423462023-10-20 11:19:36 -0500134 if (resp.blob_state & ipmiblob::StateFlags::open_read)
135 {
136 return resp.size;
137 }
138 if (resp.blob_state & ipmiblob::StateFlags::committing)
139 {
140 return std::nullopt;
141 }
142 throw ToolException("BMC blob failed to become ready");
143 });
Jie Yang328f5202021-03-16 00:52:07 -0700144}
145
Vivekanand Veeracholanc7fa2c22021-02-18 18:05:41 -0800146void* memcpyAligned(void* destination, const void* source, std::size_t size)
147{
148 std::size_t i = 0;
149 std::size_t bytesCopied = 0;
150
Willy Tufd16f6d2021-09-16 21:31:58 -0700151 if (!(reinterpret_cast<std::uintptr_t>(destination) %
152 sizeof(std::uint64_t)) &&
153 !(reinterpret_cast<std::uintptr_t>(source) % sizeof(std::uint64_t)))
Vivekanand Veeracholanc7fa2c22021-02-18 18:05:41 -0800154 {
155 auto src64 = reinterpret_cast<const volatile std::uint64_t*>(source);
156 auto dest64 = reinterpret_cast<volatile std::uint64_t*>(destination);
157
158 for (i = 0; i < size / sizeof(std::uint64_t); i++)
159 {
160 *dest64++ = *src64++;
161 bytesCopied += sizeof(std::uint64_t);
162 }
163 }
164
Patrick Williams10388362023-05-10 07:51:09 -0500165 auto srcMem8 = reinterpret_cast<const volatile std::uint8_t*>(source) +
166 bytesCopied;
167 auto destMem8 = reinterpret_cast<volatile std::uint8_t*>(destination) +
168 bytesCopied;
Vivekanand Veeracholanc7fa2c22021-02-18 18:05:41 -0800169
170 for (i = bytesCopied; i < size; i++)
171 {
172 *destMem8++ = *srcMem8++;
173 }
174
175 return destination;
176}
177
Patrick Venture01123b22019-06-20 13:49:06 -0700178} // namespace host_tool