/*
 * DF-5160 trigger module (aptest.ko) — mirrors the DF-4735/DF-5155
 * consequence-level verification pattern.
 *
 * Reproduces, in kernel context, the exact raw MSR read sequence of
 * aperf_sensor_task() (sys/dev/misc/aperf/aperf.c:157-161):
 *
 *	crit_enter();
 *	tsc = rdtsc_ordered();
 *	aperf = rdmsr(MSR_APERF);	<- aperf.c:159, raw, #GP-fatal
 *	mperf = rdmsr(MSR_MPERF);	<- aperf.c:160, raw, #GP-fatal
 *	crit_exit();
 *
 * gated in the driver only by the live CPUID.06H.ECX bit 0 check of
 * aperf_identify() (aperf.c:88-90) — no cpu_high guard (contrast
 * perfbias.c:99), no model whitelist, no fault-safe accessor.
 *
 * MOD_LOAD sequence:
 *   1. print CPUID.06H and the identify-gate evaluation
 *   2. rdmsr_safe(MSR_APERF/MSR_MPERF) — expect EFAULT(14) on a VMM/CPU
 *      that does not implement the MSR
 *   3. execute the verbatim aperf.c:158-160 body — on a faulting platform
 *      this must take "Fatal trap 9: general protection fault while in
 *      kernel mode ... Stopped at ...: rdmsr" and leave the guest dead in
 *      DDB, i.e. exactly what the stock aperf driver would do ~1s after
 *      attaching on a CPUID-lying platform (sensor_task period = 1s,
 *      aperf.c:131; first task invocation already performs the raw reads).
 */
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/thread2.h>

#include <machine/clock.h>
#include <machine/cpufunc.h>

#define MSR_MPERF	0xE7
#define MSR_APERF	0xE8

static int
aptest_modevent(module_t mod, int type, void *arg)
{
	uint64_t aperf, mperf, tsc, v;
	uint32_t regs[4];
	int err;

	switch (type) {
	case MOD_LOAD:
		/* what aperf_identify() (aperf.c:88-90) looks at */
		do_cpuid(0x00000006, regs);
		kprintf("aptest: CPUID.06H EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n",
		    regs[0], regs[1], regs[2], regs[3]);
		kprintf("aptest: aperf identify gate ECX bit0 (aperf.c:89) = %d\n",
		    (regs[2] & 1) != 0);

		/* what the stock driver never does before line 159 */
		err = rdmsr_safe(MSR_APERF, &v);
		kprintf("aptest: rdmsr_safe(MSR_APERF 0xE8) = %d\n", err);
		err = rdmsr_safe(MSR_MPERF, &v);
		kprintf("aptest: rdmsr_safe(MSR_MPERF 0xE7) = %d\n", err);

		/* verbatim aperf_sensor_task() body, aperf.c:157-161 */
		kprintf("aptest: entering aperf_sensor_task body (aperf.c:157-161)\n");
		crit_enter();
		tsc = rdtsc_ordered();
		aperf = rdmsr(MSR_APERF);	/* aperf.c:159 */
		mperf = rdmsr(MSR_MPERF);	/* aperf.c:160 */
		crit_exit();
		kprintf("aptest: survived raw rdmsr: tsc=%llu aperf=%llu mperf=%llu\n",
		    (unsigned long long)tsc, (unsigned long long)aperf,
		    (unsigned long long)mperf);
		return 0;
	default:
		return EOPNOTSUPP;
	}
}

static moduledata_t aptest_mod = {
	"aptest",
	aptest_modevent,
	NULL
};
DECLARE_MODULE(aptest, aptest_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
