blob: a332f7256708fd632671cd9d209630c72e43e28d [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef HWREG_X86MSR_H_
#define HWREG_X86MSR_H_
#include "internal.h"
#if !defined(__x86_64__) && !defined(__i386__)
#error ""x86msr.h" is for x86 only"
#endif
namespace hwreg {
// This can be passed to ReadFrom and WriteTo methods.
// The RegisterAddr object holds the whole MSR number.
struct X86MsrIo {
template <typename IntType>
void Write(IntType value, uint32_t msr) const {
static_assert(internal::IsSupportedInt<IntType>::value, "unsupported register access width");
uint64_t v = static_cast<uint64_t>(value);
// The high-order 32 bits of each register are ignored so they need not be
// cleared. uintptr_t is 32 bits on x86-32 so that values will match the
// register size, but 64 bits on x86-64 so that the compiler doesn't think
// it needs to add an instruction to clear the high bits.
uintptr_t lo = static_cast<uintptr_t>(v);
uintptr_t hi = static_cast<uintptr_t>(v >> 32);
__asm__ volatile("wrmsr" : : "c"(msr), "a"(lo), "d"(hi));
}
template <typename IntType>
IntType Read(uint32_t msr) const {
static_assert(internal::IsSupportedInt<IntType>::value, "unsupported register access width");
uint32_t lo, hi;
__asm__ volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr));
return static_cast<IntType>((static_cast<uint64_t>(hi) << 32) | lo);
}
};
} // namespace hwreg
#endif // HWREG_X86MSR_H_