/* SPDX-License-Identifier: GPL-2.0-only */

#include <console/console.h>
#include <cpu/amd/amd64_save_state.h>
#include <cpu/amd/msr.h>
#include <amdblocks/smm.h>
#include <cpu/cpu.h>
#include <cpu/x86/msr.h>
#include <stdint.h>

/*
 * For data stored in TSEG, ensure TValid is clear so R/W access can reach
 * the DRAM when not in SMM.
 */
void clear_tvalid(void)
{
	msr_t hwcr = rdmsr(HWCR_MSR);
	msr_t mask = rdmsr(SMM_MASK_MSR);
	int tvalid = !!(mask.lo & SMM_TSEG_VALID);

	if (hwcr.lo & SMM_LOCK) {
		if (!tvalid) /* not valid but locked means still accessible */
			return;

		printk(BIOS_ERR, "can't clear TValid, already locked\n");
		return;
	}

	mask.lo &= ~SMM_TSEG_VALID;
	wrmsr(SMM_MASK_MSR, mask);
}

void tseg_valid(void)
{
	msr_t mask = rdmsr(SMM_MASK_MSR);
	mask.lo |= SMM_TSEG_VALID;

	wrmsr(SMM_MASK_MSR, mask);
}

bool is_smm_locked(void)
{
	msr_t hwcr = rdmsr(HWCR_MSR);
	return hwcr.lo & SMM_LOCK ? true : false;
}

void lock_smm(void)
{
	msr_t hwcr = rdmsr(HWCR_MSR);
	hwcr.lo |= SMM_LOCK;
	wrmsr(HWCR_MSR, hwcr);
}
