blob: 7ae8c76a88d18793a7d43c8c07c54c524f6605a5 [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
25#include <chrono>
Patrick Venture01123b22019-06-20 13:49:06 -070026#include <thread>
Jie Yang328f5202021-03-16 00:52:07 -070027#include <utility>
Patrick Venture01123b22019-06-20 13:49:06 -070028
29namespace host_tool
30{
31
32/* Poll an open verification session. Handling closing the session is not yet
33 * owned by this method.
34 */
William A. Kennington IIIf88bcf32021-10-14 02:15:10 -070035void pollStatus(std::uint16_t session, ipmiblob::BlobInterface* blob)
Patrick Venture01123b22019-06-20 13:49:06 -070036{
37 using namespace std::chrono_literals;
38
39 static constexpr auto verificationSleep = 5s;
40 ipmi_flash::ActionStatus result = ipmi_flash::ActionStatus::unknown;
41
42 try
43 {
Benjamin Fair6f61af82020-05-14 10:41:13 -070044 /* sleep for 5 seconds and check 360 times, for a timeout of: 1800
45 * seconds (30 minutes).
Patrick Venture69abbc62019-08-13 13:47:36 -070046 * TODO: make this command line configurable and provide smaller
47 * default value.
48 */
Benjamin Fair6f61af82020-05-14 10:41:13 -070049 static constexpr int commandAttempts = 360;
Patrick Venture01123b22019-06-20 13:49:06 -070050 int attempts = 0;
51 bool exitLoop = false;
52
53 /* Reach back the current status from the verification service output.
54 */
55 while (attempts++ < commandAttempts)
56 {
57 ipmiblob::StatResponse resp = blob->getStat(session);
58
59 if (resp.metadata.size() != sizeof(std::uint8_t))
60 {
61 /* TODO: How do we want to handle the verification failures,
62 * because closing the session to the verify blob has a special
63 * as-of-yet not fully defined behavior.
64 */
65 std::fprintf(stderr, "Received invalid metadata response!!!\n");
66 }
67
68 result = static_cast<ipmi_flash::ActionStatus>(resp.metadata[0]);
69
70 switch (result)
71 {
72 case ipmi_flash::ActionStatus::failed:
73 std::fprintf(stderr, "failed\n");
74 exitLoop = true;
75 break;
76 case ipmi_flash::ActionStatus::unknown:
77 std::fprintf(stderr, "other\n");
78 break;
79 case ipmi_flash::ActionStatus::running:
80 std::fprintf(stderr, "running\n");
81 break;
82 case ipmi_flash::ActionStatus::success:
83 std::fprintf(stderr, "success\n");
84 exitLoop = true;
85 break;
86 default:
87 std::fprintf(stderr, "wat\n");
88 }
89
90 if (exitLoop)
91 {
92 break;
93 }
94 std::this_thread::sleep_for(verificationSleep);
95 }
96 }
97 catch (const ipmiblob::BlobException& b)
98 {
99 throw ToolException("blob exception received: " +
100 std::string(b.what()));
101 }
102
103 /* TODO: If this is reached and it's not success, it may be worth just
104 * throwing a ToolException with a timeout message specifying the final
105 * read's value.
106 *
107 * TODO: Given that excepting from certain points leaves the BMC update
108 * state machine in an inconsistent state, we need to carefully evaluate
109 * which exceptions from the lower layers allow one to try and delete the
110 * blobs to rollback the state and progress.
111 */
William A. Kennington IIIf88bcf32021-10-14 02:15:10 -0700112 if (result != ipmi_flash::ActionStatus::success)
113 {
114 throw ToolException("BMC reported failure");
115 }
Patrick Venture01123b22019-06-20 13:49:06 -0700116}
117
Jie Yang328f5202021-03-16 00:52:07 -0700118/* Poll an open blob session for reading.
119 *
120 * The committing bit indicates that the blob is not available for reading now
121 * and the reader might come back and check the state later.
122 *
123 * Polling finishes under the following conditions:
124 * - The open_read bit set -> stat successful
125 * - The open_read and committing bits unset -> stat failed;
126 * - Blob exception was received;
127 * - Time ran out.
128 * Polling continues when the open_read bit unset and committing bit set.
129 * If the blob is not open_read and not committing, then it is an error to the
130 * reader.
131 */
William A. Kennington IIIf88bcf32021-10-14 02:15:10 -0700132uint32_t pollReadReady(std::uint16_t session, ipmiblob::BlobInterface* blob)
Jie Yang328f5202021-03-16 00:52:07 -0700133{
134 using namespace std::chrono_literals;
135 static constexpr auto pollingSleep = 5s;
136 ipmiblob::StatResponse blobStatResp;
137
138 try
139 {
140 /* Polling lasts 5 minutes. When opening a version blob, the system
141 * unit defined in the version handler will extract the running version
142 * from the image on the flash.
143 */
144 static constexpr int commandAttempts = 60;
145 int attempts = 0;
146
147 while (attempts++ < commandAttempts)
148 {
149 blobStatResp = blob->getStat(session);
150
Vivekanand Veeracholan4bb6bdf2021-08-31 12:35:17 -0700151 if (blobStatResp.blob_state & ipmiblob::StateFlags::open_read)
Jie Yang328f5202021-03-16 00:52:07 -0700152 {
153 std::fprintf(stderr, "success\n");
William A. Kennington IIIf88bcf32021-10-14 02:15:10 -0700154 return blobStatResp.size;
Jie Yang328f5202021-03-16 00:52:07 -0700155 }
Vivekanand Veeracholan4bb6bdf2021-08-31 12:35:17 -0700156 else if (blobStatResp.blob_state & ipmiblob::StateFlags::committing)
Jie Yang328f5202021-03-16 00:52:07 -0700157 {
158 std::fprintf(stderr, "running\n");
159 }
160 else
161 {
162 std::fprintf(stderr, "failed\n");
William A. Kennington IIIf88bcf32021-10-14 02:15:10 -0700163 throw ToolException("BMC reported failure");
Jie Yang328f5202021-03-16 00:52:07 -0700164 }
165
166 std::this_thread::sleep_for(pollingSleep);
167 }
168 }
169 catch (const ipmiblob::BlobException& b)
170 {
171 throw ToolException("blob exception received: " +
172 std::string(b.what()));
173 }
174
William A. Kennington IIIf88bcf32021-10-14 02:15:10 -0700175 throw ToolException("Timed out waiting for BMC read ready");
Jie Yang328f5202021-03-16 00:52:07 -0700176}
177
Vivekanand Veeracholanc7fa2c22021-02-18 18:05:41 -0800178void* memcpyAligned(void* destination, const void* source, std::size_t size)
179{
180 std::size_t i = 0;
181 std::size_t bytesCopied = 0;
182
Willy Tufd16f6d2021-09-16 21:31:58 -0700183 if (!(reinterpret_cast<std::uintptr_t>(destination) %
184 sizeof(std::uint64_t)) &&
185 !(reinterpret_cast<std::uintptr_t>(source) % sizeof(std::uint64_t)))
Vivekanand Veeracholanc7fa2c22021-02-18 18:05:41 -0800186 {
187 auto src64 = reinterpret_cast<const volatile std::uint64_t*>(source);
188 auto dest64 = reinterpret_cast<volatile std::uint64_t*>(destination);
189
190 for (i = 0; i < size / sizeof(std::uint64_t); i++)
191 {
192 *dest64++ = *src64++;
193 bytesCopied += sizeof(std::uint64_t);
194 }
195 }
196
197 auto srcMem8 =
198 reinterpret_cast<const volatile std::uint8_t*>(source) + bytesCopied;
199 auto destMem8 =
200 reinterpret_cast<volatile std::uint8_t*>(destination) + bytesCopied;
201
202 for (i = bytesCopied; i < size; i++)
203 {
204 *destMem8++ = *srcMem8++;
205 }
206
207 return destination;
208}
209
Patrick Venture01123b22019-06-20 13:49:06 -0700210} // namespace host_tool