blob: 20df9155b8ef5b61c38c22f2705d555dac44bbfc [file] [log] [blame]
#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, &timestamp, 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