/*
 * df3978_rig.c -- DF-3978 in-kernel verification rig (KLD, root-only).
 *
 * Duties:
 *   MOD_LOAD          : print offsetof() constants for the CPL0 payload.
 *   kern.df3978_msrs  : live rdmsr() of IA32_SYSENTER_{CS,ESP,EIP} -- the
 *                       hardware state the finding says is left
 *                       guest-controlled after each NVMM VCPU_RUN.
 *   kern.df3978_pid=N : resolve pid via the kernel's own pfind() and dump
 *                       the proc and ucred pointers plus uid fields
 *                       (validates the offsets against real data).
 */
#include <sys/param.h>
#include <sys/types.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/ucred.h>
#include <sys/sysctl.h>
#include <machine/cpufunc.h>
#include <machine/specialreg.h>

static int g_pid = 1;

static int
df3978_msrs_handler(SYSCTL_HANDLER_ARGS)
{
	uint64_t cs, esp, eip;
	char buf[160];

	cs  = rdmsr(MSR_SYSENTER_CS);
	esp = rdmsr(MSR_SYSENTER_ESP);
	eip = rdmsr(MSR_SYSENTER_EIP);
	ksnprintf(buf, sizeof(buf), "cs=%#jx esp=%#jx eip=%#jx",
	    (uintmax_t)cs, (uintmax_t)esp, (uintmax_t)eip);
	return SYSCTL_OUT(req, buf, strlen(buf) + 1);
}
SYSCTL_PROC(_kern, OID_AUTO, df3978_msrs, CTLTYPE_STRING | CTLFLAG_RD,
    0, 0, df3978_msrs_handler, "A", "live SYSENTER MSRs");

static int
df3978_pid_handler(SYSCTL_HANDLER_ARGS)
{
	int error, t = g_pid;
	struct proc *p;

	error = sysctl_handle_int(oidp, &t, 0, req);
	if (error == 0 && req->newptr != NULL) {
		g_pid = t;
		p = pfind(g_pid);
		if (p == NULL) {
			kprintf("DF3978RIG: pid=%d NOT FOUND\n", g_pid);
		} else {
			kprintf("DF3978RIG: pid=%d proc=%p ucred=%p uid=%d "
			    "ruid=%d comm=%s OFFp_ucred=%zu OFFcr_uid=%zu "
			    "OFFcr_ruid=%zu OFFcr_svuid=%zu\n",
			    (int)p->p_pid, p, p->p_ucred,
			    (int)p->p_ucred->cr_uid,
			    (int)p->p_ucred->cr_ruid, p->p_comm,
			    (size_t)offsetof(struct proc, p_ucred),
			    (size_t)offsetof(struct ucred, cr_uid),
			    (size_t)offsetof(struct ucred, cr_ruid),
			    (size_t)offsetof(struct ucred, cr_svuid));
		}
	}
	return (error);
}
SYSCTL_PROC(_kern, OID_AUTO, df3978_pid, CTLTYPE_INT | CTLFLAG_RW,
    0, 0, df3978_pid_handler, "I", "resolve pid via pfind");

static int
df3978_modev(module_t mod, int type, void *data)
{
	switch (type) {
	case MOD_LOAD:
		kprintf("DF3978RIG: loaded. OFFp_pid=%zu OFFp_ucred=%zu "
		    "OFFp_list=%zu OFFcr_uid=%zu OFFcr_ruid=%zu "
		    "OFFcr_svuid=%zu sizeof_ucred=%zu sizeof_proc=%zu\n",
		    (size_t)offsetof(struct proc, p_pid),
		    (size_t)offsetof(struct proc, p_ucred),
		    (size_t)offsetof(struct proc, p_list),
		    (size_t)offsetof(struct ucred, cr_uid),
		    (size_t)offsetof(struct ucred, cr_ruid),
		    (size_t)offsetof(struct ucred, cr_svuid),
		    (size_t)sizeof(struct ucred),
		    (size_t)sizeof(struct proc));
		break;
	case MOD_UNLOAD:
		kprintf("DF3978RIG: unloaded\n");
		break;
	default:
		break;
	}
	return 0;
}

static moduledata_t df3978_mod = { "df3978rig", df3978_modev, NULL };
DECLARE_MODULE(df3978rig, df3978_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
