blob: a20baac23ca25c752e515711c6ea474cbd66c2b4 [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 */
35bool pollStatus(std::uint16_t session, ipmiblob::BlobInterface* blob)
36{
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 */
112 return (result == ipmi_flash::ActionStatus::success);
113}
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 */
129std::pair<bool, uint32_t> pollReadReady(std::uint16_t session,
130 ipmiblob::BlobInterface* blob)
131{
132 using namespace std::chrono_literals;
133 static constexpr auto pollingSleep = 5s;
134 ipmiblob::StatResponse blobStatResp;
135
136 try
137 {
138 /* Polling lasts 5 minutes. When opening a version blob, the system
139 * unit defined in the version handler will extract the running version
140 * from the image on the flash.
141 */
142 static constexpr int commandAttempts = 60;
143 int attempts = 0;
144
145 while (attempts++ < commandAttempts)
146 {
147 blobStatResp = blob->getStat(session);
148
Vivekanand Veeracholan4bb6bdf2021-08-31 12:35:17 -0700149 if (blobStatResp.blob_state & ipmiblob::StateFlags::open_read)
Jie Yang328f5202021-03-16 00:52:07 -0700150 {
151 std::fprintf(stderr, "success\n");
152 return std::make_pair(true, blobStatResp.size);
153 }
Vivekanand Veeracholan4bb6bdf2021-08-31 12:35:17 -0700154 else if (blobStatResp.blob_state & ipmiblob::StateFlags::committing)
Jie Yang328f5202021-03-16 00:52:07 -0700155 {
156 std::fprintf(stderr, "running\n");
157 }
158 else
159 {
160 std::fprintf(stderr, "failed\n");
161 return std::make_pair(false, 0);
162 }
163
164 std::this_thread::sleep_for(pollingSleep);
165 }
166 }
167 catch (const ipmiblob::BlobException& b)
168 {
169 throw ToolException("blob exception received: " +
170 std::string(b.what()));
171 }
172
173 return std::make_pair(false, 0);
174}
175
Vivekanand Veeracholanc7fa2c22021-02-18 18:05:41 -0800176void* memcpyAligned(void* destination, const void* source, std::size_t size)
177{
178 std::size_t i = 0;
179 std::size_t bytesCopied = 0;
180
181 if ((alignof(destination) == alignof(std::uint64_t)) &&
182 (alignof(source) == alignof(std::uint64_t)))
183 {
184 auto src64 = reinterpret_cast<const volatile std::uint64_t*>(source);
185 auto dest64 = reinterpret_cast<volatile std::uint64_t*>(destination);
186
187 for (i = 0; i < size / sizeof(std::uint64_t); i++)
188 {
189 *dest64++ = *src64++;
190 bytesCopied += sizeof(std::uint64_t);
191 }
192 }
193
194 auto srcMem8 =
195 reinterpret_cast<const volatile std::uint8_t*>(source) + bytesCopied;
196 auto destMem8 =
197 reinterpret_cast<volatile std::uint8_t*>(destination) + bytesCopied;
198
199 for (i = bytesCopied; i < size; i++)
200 {
201 *destMem8++ = *srcMem8++;
202 }
203
204 return destination;
205}
206
Patrick Venture01123b22019-06-20 13:49:06 -0700207} // namespace host_tool