/*
 * @author  xamidev <xamidev@riseup.net>
 * @brief   x86 MSR C wrappers
 * @description
 * Wrapper functions to access Model Specific Registers
 *
 * @license GPL-3.0-only
 */

#include <stdint.h>
#include <stdbool.h>
#include <arch/x86.h>

/*
 * rdmsr - Read from MSR
 * @msr: model specific register number 
 *
 * Read a 64-bit word from a Model Specific Register.
 * Wrapper for the "rdmsr" instruction. It originally
 * outputs to two 32-bit registers (EDX:EAX), so the
 * function does the job of uniting them as a 64-bit
 * value for us.
 *
 * Return:
 * <value> - value read from MSR
 */
uint64_t rdmsr(uint32_t msr)
{
    uint32_t low;
    uint32_t high;

    __asm__ volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr));

    return ((uint64_t)high << 32) | low;
}

/*
 * wrmsr - Write to MSR
 * @msr: model specific register number 
 *
 * Write a 64-bit value to a Model Specific Register.
 */
void wrmsr(uint32_t msr, uint64_t value)
{
    uint32_t low = (uint32_t)(value & 0xFFFFFFFF);
    uint32_t high = (uint32_t)(value >> 32);

    __asm__ volatile("wrmsr" : : "c"(msr), "a"(low), "d"(high) : "memory");
}

/*
 * x86_has_msr - Test for MSR support
 *
 * Checks if CPU supports Model Specific Registers
 * using CPUID.01h:EDX[bit 5].
 *
 * Return:
 * true  - MSR are supported
 * false - MSR are not supported 
 */
bool x86_has_msr()
{
    uint32_t eax, ebx, ecx, edx;
    cpuid(1, &eax, &ebx, &ecx, &edx);
    return (edx & (1 << 5)) != 0;
}