/*
 * DF-5155 trigger — perfbias.c raw MSR pair on a CPUID-lying platform.
 *
 * Executes the exact instruction sequence of perfbias_set_handler()
 * (sys/dev/powermng/perfbias/perfbias.c:178-179):
 *
 *	wrmsr(INTEL_MSR_PERF_BIAS, hint);	// 0x1b0
 *	hint = rdmsr(INTEL_MSR_PERF_BIAS);
 *
 * First exercises the fault-safe variants (rdmsr_safe/wrmsr_safe) to show
 * what the recommended fix would see on a lying platform, then performs the
 * raw pair. On any CPU/VMM that sets CPUID.06H.ECX bit 3 (SETBH) without
 * implementing MSR 0x1b0, the raw wrmsr takes a fatal #GP in kernel mode
 * (Fatal trap 9) -> DDB -> system down.
 */
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <machine/cpufunc.h>

#define INTEL_MSR_PERF_BIAS	0x1b0

static int
pbtest_modevent(module_t mod, int type, void *data)
{
	uint64_t val = 0;
	int error;

	switch (type) {
	case MOD_LOAD:
		kprintf("pbtest: rdmsr_safe(MSR_IA32_ENERGY_PERF_BIAS=0x1b0)...\n");
		error = rdmsr_safe(INTEL_MSR_PERF_BIAS, &val);
		kprintf("pbtest: rdmsr_safe -> error %d, val %#llx\n",
		    error, (unsigned long long)val);

		kprintf("pbtest: wrmsr_safe(0x1b0, 7)...\n");
		error = wrmsr_safe(INTEL_MSR_PERF_BIAS, 7);
		kprintf("pbtest: wrmsr_safe -> error %d\n", error);

		kprintf("pbtest: raw wrmsr now (perfbias.c:178 path) -- expect #GP panic\n\n");
		wrmsr(INTEL_MSR_PERF_BIAS, 7);		/* perfbias.c:178 */
		kprintf("pbtest: raw wrmsr survived\n");

		val = rdmsr(INTEL_MSR_PERF_BIAS);	/* perfbias.c:179 */
		kprintf("pbtest: raw rdmsr -> %#llx\n",
		    (unsigned long long)val);
		return 0;
	case MOD_UNLOAD:
		return 0;
	}
	return EOPNOTSUPP;
}

static moduledata_t pbtest_mod = {
	"pbtest",
	pbtest_modevent,
	NULL
};

DECLARE_MODULE(pbtest, pbtest_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
