/*
 * DF-5620 rig helper -- substitutes ONLY the missing CPUID advertisement.
 *
 * This QEMU 7.2 reports CPUID.05H.ECX = 0x2 (INTBRK) and masks
 * CPUID.01H:ECX.MON under TCG, so the stock acpi_cst_cx_mwait_setup()
 * (acpi_cstate_machdep.c:149-153) would bail with EOPNOTSUPP before ever
 * reaching the hint-validation/error-path code under test -- the
 * DF-5155/DF-5160 "VMM lies about CPUID" premise, constructed here
 * deliberately (same methodology as DF-5483 estforce.ko).
 *
 * cpu_feature2/cpu_mwait_feature are boot globals written by EVERY cpu's
 * identify_cpu() (identcpu.c:645/649), and the APs come up between
 * SI_BOOT2_START_APS and SI_SUB_DRIVERS, so a MOD_LOAD-time write is
 * clobbered.  We therefore re-force both words from a SYSINIT at
 * SI_SUB_CONFIGURE/SI_ORDER_FIRST -- after all cpu idents, immediately
 * before acpi0/cpu_cst probe.  Everything afterwards is the genuine stock
 * driver.
 *
 * NOTE: cpu_mwait_cx_info[] subcnts stay zero (cpu_mwait_attach() ran before
 * us and bailed), so every hint is "invalid" to cpu_mwait_hint_valid() --
 * exactly the scenario under test (a REJECTED descriptor).  The default idle
 * hook remains the static "sti; hlt" (machdep.c:1115); the ACPI idle hook
 * only ever selects the (valid) C1 halt state here, so the late feature
 * words cannot destabilize the boot idle path.
 */
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <machine/cputypes.h>
#include <machine/md_var.h>
#include <machine/specialreg.h>

static void
mwaitforce_force(void)
{
	cpu_feature2 |= CPUID2_MON;
	cpu_mwait_feature |= CPUID_MWAIT_EXT | CPUID_MWAIT_INTBRK;
	kprintf("mwaitforce: cpu_feature2 |= MON (%#x), "
	    "cpu_mwait_feature |= EXT|INTBRK (%#x)\n",
	    cpu_feature2, cpu_mwait_feature);
}

static void
mwaitforce_late(void *unused __unused)
{
	/* After all AP identify_cpu()s, right before device configure(). */
	mwaitforce_force();
}
SYSINIT(mwaitforce_late, SI_SUB_CONFIGURE, SI_ORDER_FIRST, mwaitforce_late,
    NULL);

static int
mwaitforce_modevent(module_t mod, int type, void *data)
{
	switch (type) {
	case MOD_LOAD:
		kprintf("mwaitforce: loaded (force happens at SI_SUB_CONFIGURE)\n");
		return 0;
	case MOD_UNLOAD:
		return 0;
	}
	return EOPNOTSUPP;
}

static moduledata_t mwaitforce_mod = {
	"mwaitforce",
	mwaitforce_modevent,
	NULL
};
DECLARE_MODULE(mwaitforce, mwaitforce_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
MODULE_VERSION(mwaitforce, 1);
