| #pragma once |
| |
| #include "cper.hpp" |
| |
| #include <chrono> |
| #include <concepts> |
| |
| namespace uefi::cper |
| { |
| template <typename T> |
| concept ByteLike = std::is_trivially_copyable_v<T> && sizeof(T) == 1; |
| |
| /** |
| * @brief Helper function to create a UTC UEFI CPER timestamp from a |
| * std::chrono time point. |
| * https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#record-header |
| * |
| * @param[in] timeOfCollection - A std::chrono time_point representing the time |
| * the fault was detected by the system software. |
| * @param[in] isPrecise - Bool which indicates if the time is precise. |
| * |
| * @param[out] A uefi cper timestamp as uint64_t. |
| */ |
| uint64_t createCperTimestamp( |
| const std::chrono::time_point<std::chrono::system_clock> timeOfCollection, |
| const bool isPrecise = true) |
| { |
| // Number of years in a century. |
| constexpr int kCentury = 100; |
| |
| // The tm_year counts the number of years since 1900. |
| // https://en.cppreference.com/w/c/chrono/tm |
| constexpr int kTmYearOffset = 1900; |
| |
| // UEFI expects the isPrecise byte bits [1:7] to be zero. |
| const uint8_t isPreciseBit = 0 | (isPrecise & 0x1); |
| |
| const time_t tt = std::chrono::system_clock::to_time_t(timeOfCollection); |
| const tm utcTime = *gmtime(&tt); |
| |
| // The uefi timestamp breaks the calendar year into two bytes |
| // representing the number of centuries and number of years. |
| const int calendarYear = utcTime.tm_year + kTmYearOffset; |
| const uint8_t year = calendarYear % kCentury; |
| const uint8_t century = calendarYear / kCentury; |
| |
| const Timestamp timestamp(utcTime.tm_sec, utcTime.tm_min, utcTime.tm_hour, |
| isPreciseBit, utcTime.tm_mday, utcTime.tm_mon, |
| year, century); |
| |
| uint64_t ret; |
| memcpy(&ret, ×tamp, sizeof(ret)); |
| return ret; |
| } |
| |
| template <ByteLike ByteType> |
| class SeqMemcopy |
| { |
| public: |
| // Prevent the class from outliving the baseDest pointer. |
| SeqMemcopy() = delete; |
| SeqMemcopy(const SeqMemcopy&) = delete; |
| SeqMemcopy& operator=(const SeqMemcopy&) = delete; |
| |
| /** |
| * @brief Manages sequentially copying chunks of data to a contiguous memory |
| * block. |
| * |
| * @param[in] baseDest - The memory location to copy to. |
| */ |
| SeqMemcopy(std::span<ByteType> baseDest) : baseDest_(baseDest), offset_(0) |
| {} |
| |
| /** |
| * @brief Copies the src to the next section in the dest address. |
| * |
| * @param[in] src - The source address to copy from. |
| * @param[in] srcSize - The source size. |
| * |
| * @throws out_of_range If source size goes out of the destinations bounds. |
| */ |
| void copy(const void* src, const uint64_t srcSize) |
| { |
| if ((offset_ + srcSize) > baseDest_.size_bytes()) |
| { |
| throw std::out_of_range( |
| "Attempt to copy out of the destinations bounds"); |
| } |
| |
| memcpy(baseDest_.data() + offset_, src, srcSize); |
| offset_ += srcSize; |
| } |
| |
| private: |
| std::span<ByteType> baseDest_; |
| uint64_t offset_; |
| }; |
| } // namespace uefi::cper |