/*
 * DF-5688 — in-kernel PANIC proof (deliberately crashes the kernel).
 *
 * Runs the 5-op sequence from the rig's minimal_panic mode against the
 * real kernel idr; the second phantom decrement + one legit remove
 * drive a cumulative 'allocated' counter to -1 and the kernel's own
 * KKASSERT(idp->idr_nodes[id].allocated >= 0) in idr_reserve()
 * (sys/libkern/linux_idr.c:197) fires -> panic().
 *
 *   chain(289) = {289, 287, 255};  chain(287) = {287, 255}
 *   alloc(289):        289:1  287:1  255:1
 *   bogus remove(287): 289:1  287:0  255:0    (guard passes)
 *   alloc(290):        290:1  289:2  287:1  255:1
 *   bogus remove(287): 290:1  289:2  287:0  255:0
 *   legit remove(290): 290:0  289:1  287:-1 255:-1  <- KKASSERT panic
 */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/module.h>
#include <sys/idr.h>

static void
df5688p_run(void)
{
	struct idr idr;
	int id;

	idr_init(&idr);

	id = idr_alloc(&idr, (void *)0xdead0001UL, 289, 290, 0);
	kprintf("df5688p[1]: idr_alloc(A, 289, 290, 0) -> %d "
	    "(nodes[287]=%d nodes[255]=%d)\n", id,
	    idr.idr_nodes[287].allocated, idr.idr_nodes[255].allocated);

	kprintf("df5688p[2]: idr_remove(287) [NEVER allocated] -> %p "
	    "(nodes[287]=%d nodes[255]=%d)\n", idr_remove(&idr, 287),
	    idr.idr_nodes[287].allocated, idr.idr_nodes[255].allocated);

	id = idr_alloc(&idr, (void *)0xdead0002UL, 290, 0, 0);
	kprintf("df5688p[3]: idr_alloc(B, 290, 0, 0) -> %d "
	    "(nodes[287]=%d nodes[255]=%d)\n", id,
	    idr.idr_nodes[287].allocated, idr.idr_nodes[255].allocated);

	kprintf("df5688p[4]: idr_remove(287) [NEVER allocated] -> %p "
	    "(nodes[287]=%d nodes[255]=%d)\n", idr_remove(&idr, 287),
	    idr.idr_nodes[287].allocated, idr.idr_nodes[255].allocated);

	kprintf("df5688p[5]: idr_remove(290) [live] -> about to decrement "
	    "chain through nodes[287]=%d ...\n",
	    idr.idr_nodes[287].allocated);

	kprintf("df5688p[5]: idr_remove(290) -> %p\n",
	    idr_remove(&idr, 290));

	kprintf("df5688p: survived (unexpectedly)\n");
	idr_destroy(&idr);
}

static int
df5688p_handler(module_t mod, int type, void *data)
{
	switch (type) {
	case MOD_LOAD:
		df5688p_run();
		return (0);
	default:
		return (0);
	}
}

static moduledata_t df5688p_mod = {
	"df5688p",
	df5688p_handler,
	NULL
};

DECLARE_MODULE(df5688p, df5688p_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
MODULE_VERSION(df5688p, 1);
