/*
 * DF-5160 CPUID-lie module (lie.ko) — substitutes ONLY the missing CPUID
 * advertisement, exactly the DF-4735-documented technique:
 *
 * It force-adds an "aperf" child to each cpuN device, bypassing the
 * aperf_identify() CPUID.06H.ECX bit0 gate (aperf.c:88-90) that this VMM
 * keeps closed by masking the bit. The STOCK, unmodified aperf driver
 * (aperf.ko built from /usr/src/sys/dev/misc/aperf/aperf.c) then probes,
 * attaches, registers its 1s sensor task — and its aperf_sensor_task()
 * executes the raw rdmsr(MSR_APERF/MSR_MPERF) pair (aperf.c:159-160) on a
 * platform where those MSRs fault -> driver-level fatal trap 9.
 *
 * Root-only kld; no unprivileged surface. It exists purely to prove the
 * consequence on a VMM whose own masking policy demonstrates the
 * lying-CPUID class (KVM strips ECX bit0 because it does not virtualize
 * the MSR, while the bare Skylake host does have the bit set).
 */
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/bus.h>

static int
lie_modevent(module_t mod, int type, void *arg)
{
	devclass_t dc;
	device_t child, parent;
	int i, maxu, rc;

	switch (type) {
	case MOD_LOAD:
		dc = devclass_find("cpu");
		if (dc == NULL) {
			kprintf("lie: no cpu devclass\n");
			return ENODEV;
		}
		maxu = devclass_get_maxunit(dc);
		kprintf("lie: forcing aperf attach on %d cpu device(s) "
		    "(CPUID lie for aperf.c:88-90 gate)\n", maxu);
		for (i = 0; i < maxu; i++) {
			parent = devclass_get_device(dc, i);
			if (parent == NULL)
				continue;
			if (device_find_child(parent, "aperf", -1) != NULL)
				continue;
			child = device_add_child(parent, "aperf", -1);
			if (child == NULL) {
				kprintf("lie: device_add_child failed cpu%d\n", i);
				continue;
			}
			rc = device_probe_and_attach(child);
			kprintf("lie: cpu%d aperf probe/attach rc=%d\n", i, rc);
		}
		return 0;
	default:
		return EOPNOTSUPP;
	}
}

static moduledata_t lie_mod = {
	"lie",
	lie_modevent,
	NULL
};
DECLARE_MODULE(lie, lie_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
