#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <endian.h>
#include "out.h"
#include "pool_hdr.h"
#if defined(__x86_64) || defined(_M_X64)
#define PMDK_MACHINE PMDK_MACHINE_X86_64
#define PMDK_MACHINE_CLASS PMDK_MACHINE_CLASS_64
#elif defined(__aarch64__)
#define PMDK_MACHINE PMDK_MACHINE_AARCH64
#define PMDK_MACHINE_CLASS PMDK_MACHINE_CLASS_64
#else
#error unable to recognize ISA at compile time
#endif
static uint8_t
arch_data(void)
{
uint16_t word = (PMDK_DATA_BE << 8) + PMDK_DATA_LE;
return ((uint8_t *)&word)[0];
}
void
util_get_arch_flags(struct arch_flags *arch_flags)
{
memset(arch_flags, 0, sizeof(*arch_flags));
arch_flags->machine = PMDK_MACHINE;
arch_flags->machine_class = PMDK_MACHINE_CLASS;
arch_flags->data = arch_data();
arch_flags->alignment_desc = alignment_desc();
}
void
util_convert2le_hdr(struct pool_hdr *hdrp)
{
hdrp->major = htole32(hdrp->major);
hdrp->compat_features = htole32(hdrp->compat_features);
hdrp->incompat_features = htole32(hdrp->incompat_features);
hdrp->ro_compat_features = htole32(hdrp->ro_compat_features);
hdrp->arch_flags.alignment_desc =
htole64(hdrp->arch_flags.alignment_desc);
hdrp->arch_flags.machine = htole16(hdrp->arch_flags.machine);
hdrp->crtime = htole64(hdrp->crtime);
hdrp->checksum = htole64(hdrp->checksum);
}
void
util_convert2h_hdr_nocheck(struct pool_hdr *hdrp)
{
hdrp->major = le32toh(hdrp->major);
hdrp->compat_features = le32toh(hdrp->compat_features);
hdrp->incompat_features = le32toh(hdrp->incompat_features);
hdrp->ro_compat_features = le32toh(hdrp->ro_compat_features);
hdrp->crtime = le64toh(hdrp->crtime);
hdrp->arch_flags.machine = le16toh(hdrp->arch_flags.machine);
hdrp->arch_flags.alignment_desc =
le64toh(hdrp->arch_flags.alignment_desc);
hdrp->checksum = le64toh(hdrp->checksum);
}
int
util_convert_hdr(struct pool_hdr *hdrp)
{
LOG(3, "hdrp %p", hdrp);
util_convert2h_hdr_nocheck(hdrp);
if (hdrp->major == 0) {
ERR("invalid major version (0)");
return 0;
}
if (!util_checksum(hdrp, sizeof(*hdrp), &hdrp->checksum, 0)) {
ERR("invalid checksum of pool header");
return 0;
}
LOG(3, "valid header, signature \"%.8s\"", hdrp->signature);
return 1;
}
int
util_convert_hdr_remote(struct pool_hdr *hdrp)
{
LOG(3, "hdrp %p", hdrp);
util_convert2h_hdr_nocheck(hdrp);
if (!util_checksum(hdrp, sizeof(*hdrp), &hdrp->checksum, 0)) {
ERR("invalid checksum of pool header");
return 0;
}
LOG(3, "valid header, signature \"%.8s\"", hdrp->signature);
return 1;
}
int
util_check_arch_flags(const struct arch_flags *arch_flags)
{
struct arch_flags cur_af;
int ret = 0;
util_get_arch_flags(&cur_af);
if (!util_is_zeroed(&arch_flags->reserved,
sizeof(arch_flags->reserved))) {
ERR("invalid reserved values");
ret = -1;
}
if (arch_flags->machine != cur_af.machine) {
ERR("invalid machine value");
ret = -1;
}
if (arch_flags->data != cur_af.data) {
ERR("invalid data value");
ret = -1;
}
if (arch_flags->machine_class != cur_af.machine_class) {
ERR("invalid machine_class value");
ret = -1;
}
if (arch_flags->alignment_desc != cur_af.alignment_desc) {
ERR("invalid alignment_desc value");
ret = -1;
}
return ret;
}
int
util_feature_check(struct pool_hdr *hdrp, uint32_t incompat,
uint32_t ro_compat, uint32_t compat)
{
LOG(3, "hdrp %p incompat %#x ro_compat %#x compat %#x",
hdrp, incompat, ro_compat, compat);
#define GET_NOT_MASKED_BITS(x, mask) ((x) & ~(mask))
uint32_t ubits;
ubits = GET_NOT_MASKED_BITS(hdrp->incompat_features, incompat);
if (ubits) {
ERR("unsafe to continue due to unknown incompat "\
"features: %#x", ubits);
errno = EINVAL;
return -1;
}
ubits = GET_NOT_MASKED_BITS(hdrp->ro_compat_features, ro_compat);
if (ubits) {
ERR("switching to read-only mode due to unknown ro_compat "\
"features: %#x", ubits);
return 0;
}
ubits = GET_NOT_MASKED_BITS(hdrp->compat_features, compat);
if (ubits) {
LOG(3, "ignoring unknown compat features: %#x", ubits);
}
#undef GET_NOT_MASKED_BITS
return 1;
}