blob: 6186f97d06ece76316a1dcb7cd4b73e3936c0a93 [file] [log] [blame]
Kuiying Wang3a044402019-02-19 15:00:11 +08001/*
2// Copyright (c) 2019 Intel Corporation
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#include "post_code.hpp"
ZhikuiRen993d4dd2020-01-29 14:25:44 -080017
Jonathan Domanc7fed5c2022-11-23 11:14:42 -080018#include <iomanip>
ZhikuiRen993d4dd2020-01-29 14:25:44 -080019
20void PostCode::deleteAll()
21{
Jonathan Domanc7fed5c2022-11-23 11:14:42 -080022 std::uintmax_t n = fs::remove_all(postCodeListPath);
ZhikuiRen993d4dd2020-01-29 14:25:44 -080023 std::cerr << "clearPostCodes deleted " << n << " files in "
Jonathan Domanc7fed5c2022-11-23 11:14:42 -080024 << postCodeListPath << std::endl;
25 fs::create_directories(postCodeListPath);
ZhikuiRen993d4dd2020-01-29 14:25:44 -080026 postCodes.clear();
Ravi Tejab84fea42021-06-03 02:09:15 -050027 currentBootCycleIndex = 0;
28 currentBootCycleCount(0);
ZhikuiRen993d4dd2020-01-29 14:25:44 -080029}
30
Manojkiran Eda84a4c192021-02-25 15:23:42 +053031std::vector<postcode_t> PostCode::getPostCodes(uint16_t index)
Kuiying Wang3a044402019-02-19 15:00:11 +080032{
Manojkiran Eda84a4c192021-02-25 15:23:42 +053033 std::vector<postcode_t> codesVec;
ZhikuiRen993d4dd2020-01-29 14:25:44 -080034 if (1 == index && !postCodes.empty())
35 {
Manojkiran Edade8d3a52021-12-05 12:51:07 +053036 std::transform(postCodes.begin(), postCodes.end(),
37 std::back_inserter(codesVec),
38 [](const auto& kv) { return kv.second; });
ZhikuiRen993d4dd2020-01-29 14:25:44 -080039 }
40 else
41 {
42 uint16_t bootNum = getBootNum(index);
Kuiying Wang3a044402019-02-19 15:00:11 +080043
ZhikuiRen993d4dd2020-01-29 14:25:44 -080044 decltype(postCodes) codes;
Jonathan Domanc7fed5c2022-11-23 11:14:42 -080045 deserializePostCodes(postCodeListPath / std::to_string(bootNum), codes);
Manojkiran Edade8d3a52021-12-05 12:51:07 +053046 std::transform(codes.begin(), codes.end(), std::back_inserter(codesVec),
47 [](const auto& kv) { return kv.second; });
ZhikuiRen993d4dd2020-01-29 14:25:44 -080048 }
49 return codesVec;
50}
51
Manojkiran Eda84a4c192021-02-25 15:23:42 +053052std::map<uint64_t, postcode_t>
53 PostCode::getPostCodesWithTimeStamp(uint16_t index)
ZhikuiRen993d4dd2020-01-29 14:25:44 -080054{
55 if (1 == index && !postCodes.empty())
56 {
Kuiying Wang3a044402019-02-19 15:00:11 +080057 return postCodes;
ZhikuiRen993d4dd2020-01-29 14:25:44 -080058 }
59
60 uint16_t bootNum = getBootNum(index);
61 decltype(postCodes) codes;
Jonathan Domanc7fed5c2022-11-23 11:14:42 -080062 deserializePostCodes(postCodeListPath / std::to_string(bootNum), codes);
Kuiying Wang3a044402019-02-19 15:00:11 +080063 return codes;
64}
ZhikuiRen993d4dd2020-01-29 14:25:44 -080065
Manojkiran Eda84a4c192021-02-25 15:23:42 +053066void PostCode::savePostCodes(postcode_t code)
Kuiying Wang3a044402019-02-19 15:00:11 +080067{
ZhikuiRen993d4dd2020-01-29 14:25:44 -080068 // steady_clock is a monotonic clock that is guaranteed to never be adjusted
69 auto postCodeTimeSteady = std::chrono::steady_clock::now();
70 uint64_t tsUS = std::chrono::duration_cast<std::chrono::microseconds>(
71 std::chrono::system_clock::now().time_since_epoch())
72 .count();
73
74 if (postCodes.empty())
75 {
76 firstPostCodeTimeSteady = postCodeTimeSteady;
77 firstPostCodeUsSinceEpoch = tsUS; // uS since epoch for 1st post code
78 incrBootCycle();
79 }
80 else
81 {
82 // calculating tsUS so it is monotonic within the same boot
Alan Kuof5e52db2021-12-23 10:57:05 +080083 tsUS = firstPostCodeUsSinceEpoch +
84 std::chrono::duration_cast<std::chrono::microseconds>(
85 postCodeTimeSteady - firstPostCodeTimeSteady)
86 .count();
ZhikuiRen993d4dd2020-01-29 14:25:44 -080087 }
88
89 postCodes.insert(std::make_pair(tsUS, code));
Bonnie Loc1819372022-10-27 17:14:55 +080090 if (postCodes.size() > MAX_POST_CODE_SIZE_PER_CYCLE)
91 {
92 postCodes.erase(postCodes.begin());
93 }
Jonathan Domanc7fed5c2022-11-23 11:14:42 -080094 serialize(postCodeListPath);
ZhikuiRen993d4dd2020-01-29 14:25:44 -080095
Alan Kuo0171dd62021-04-15 10:47:32 +080096#ifdef ENABLE_BIOS_POST_CODE_LOG
Alan Kuof5e52db2021-12-23 10:57:05 +080097 uint64_t usTimeOffset = tsUS - firstPostCodeUsSinceEpoch;
Alan Kuo0171dd62021-04-15 10:47:32 +080098 std::ostringstream hexCode;
99 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
100 << std::get<0>(code);
101
102 std::ostringstream timeOffsetStr;
103 // Set Fixed-Point Notation
104 timeOffsetStr << std::fixed;
105 // Set precision to 4 digits
106 timeOffsetStr << std::setprecision(4);
107 // Add double to stream
108 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
109
110 phosphor::logging::log<phosphor::logging::level::INFO>(
111 "BIOS POST Code",
112 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s",
Alan Kuof5e52db2021-12-23 10:57:05 +0800113 "OpenBMC.0.2.BIOSPOSTCode"),
Alan Kuo0171dd62021-04-15 10:47:32 +0800114 phosphor::logging::entry(
115 "REDFISH_MESSAGE_ARGS=%d,%s,%s", currentBootCycleIndex,
116 timeOffsetStr.str().c_str(), hexCode.str().c_str()));
117#endif
118
Kuiying Wang3a044402019-02-19 15:00:11 +0800119 return;
120}
121
Jonathan Domanc7fed5c2022-11-23 11:14:42 -0800122fs::path PostCode::serialize(const fs::path& path)
Kuiying Wang3a044402019-02-19 15:00:11 +0800123{
124 try
125 {
Jonathan Domanc7fed5c2022-11-23 11:14:42 -0800126 std::ofstream osIdx(path / CurrentBootCycleIndexName, std::ios::binary);
ZhikuiRen993d4dd2020-01-29 14:25:44 -0800127 cereal::JSONOutputArchive idxArchive(osIdx);
128 idxArchive(currentBootCycleIndex);
129
130 uint16_t count = currentBootCycleCount();
Jonathan Domanc7fed5c2022-11-23 11:14:42 -0800131 std::ofstream osCnt(path / CurrentBootCycleCountName, std::ios::binary);
ZhikuiRen993d4dd2020-01-29 14:25:44 -0800132 cereal::JSONOutputArchive cntArchive(osCnt);
133 cntArchive(count);
Kuiying Wang3a044402019-02-19 15:00:11 +0800134
Jonathan Domanc7fed5c2022-11-23 11:14:42 -0800135 std::ofstream osPostCodes(path / std::to_string(currentBootCycleIndex));
Kuiying Wang3a044402019-02-19 15:00:11 +0800136 cereal::JSONOutputArchive oarchivePostCodes(osPostCodes);
137 oarchivePostCodes(postCodes);
138 }
Patrick Williams7cc8ea62021-10-06 12:40:56 -0500139 catch (const cereal::Exception& e)
Kuiying Wang3a044402019-02-19 15:00:11 +0800140 {
141 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
142 return "";
143 }
144 catch (const fs::filesystem_error& e)
145 {
146 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
147 return "";
148 }
149 return path;
150}
151
152bool PostCode::deserialize(const fs::path& path, uint16_t& index)
153{
154 try
155 {
156 if (fs::exists(path))
157 {
Jonathan Domanc7fed5c2022-11-23 11:14:42 -0800158 std::ifstream is(path, std::ios::in | std::ios::binary);
Kuiying Wang3a044402019-02-19 15:00:11 +0800159 cereal::JSONInputArchive iarchive(is);
160 iarchive(index);
161 return true;
162 }
163 return false;
164 }
Patrick Williams7cc8ea62021-10-06 12:40:56 -0500165 catch (const cereal::Exception& e)
Kuiying Wang3a044402019-02-19 15:00:11 +0800166 {
167 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
168 return false;
169 }
170 catch (const fs::filesystem_error& e)
171 {
172 return false;
173 }
174
175 return false;
176}
177
178bool PostCode::deserializePostCodes(const fs::path& path,
Manojkiran Eda84a4c192021-02-25 15:23:42 +0530179 std::map<uint64_t, postcode_t>& codes)
Kuiying Wang3a044402019-02-19 15:00:11 +0800180{
181 try
182 {
183 if (fs::exists(path))
184 {
Jonathan Domanc7fed5c2022-11-23 11:14:42 -0800185 std::ifstream is(path, std::ios::in | std::ios::binary);
Kuiying Wang3a044402019-02-19 15:00:11 +0800186 cereal::JSONInputArchive iarchive(is);
187 iarchive(codes);
188 return true;
189 }
190 return false;
191 }
Patrick Williams7cc8ea62021-10-06 12:40:56 -0500192 catch (const cereal::Exception& e)
Kuiying Wang3a044402019-02-19 15:00:11 +0800193 {
194 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
195 return false;
196 }
197 catch (const fs::filesystem_error& e)
198 {
199 return false;
200 }
Kuiying Wang3a044402019-02-19 15:00:11 +0800201 return false;
202}
ZhikuiRen993d4dd2020-01-29 14:25:44 -0800203
204void PostCode::incrBootCycle()
205{
206 if (currentBootCycleIndex >= maxBootCycleNum())
207 {
208 currentBootCycleIndex = 1;
209 }
210 else
211 {
212 currentBootCycleIndex++;
213 }
214 currentBootCycleCount(std::min(
215 maxBootCycleNum(), static_cast<uint16_t>(currentBootCycleCount() + 1)));
216}
217
218uint16_t PostCode::getBootNum(const uint16_t index) const
219{
220 // bootNum assumes the oldest archive is boot number 1
221 // and the current boot number equals bootCycleCount
222 // map bootNum back to bootIndex that was used to archive postcode
223 uint16_t bootNum = currentBootCycleIndex;
224 if (index > bootNum) // need to wrap around
225 {
226 bootNum = (maxBootCycleNum() + currentBootCycleIndex) - index + 1;
227 }
228 else
229 {
230 bootNum = currentBootCycleIndex - index + 1;
231 }
232 return bootNum;
Kumar Thangavelfd45f782020-09-01 22:59:00 +0530233}