⬢ DragonFlyBSD Kernel Audit
DF-4795 / mcmsg_demo.c
← back to finding ↓ download raw
/*
 * DF-4794 / DF-4795 logic demonstrator -- NOT a kernel PoC.
 *
 * Replays the exact msgbuf arithmetic of e1000_update_mc_addr_list_vf()
 * (sys/dev/netif/ig_hal/e1000_vf.c:400-437) for the current DragonFly
 * ordering vs the fixed (upstream FreeBSD) ordering, using the real macro
 * values from e1000_mbx.h (62, 74, 80, 82). Also reports which bytes of
 * the 16-word msgbuf remain UNINITIALIZED kernel stack when
 * mc_addr_count < 30: e1000_write_msg_read_ack() (e1000_vf.c:380-389,436)
 * hands all E1000_VFMAILBOX_SIZE(16) words to write_posted(), and
 * e1000_write_mbx_vf() copies all `size` words verbatim into the
 * E1000_VMBMEM registers the PF (hypervisor) reads (e1000_mbx.c:476-477).
 *
 * Deterministic arithmetic only -- no hardware needed, and it claims
 * nothing beyond what the source ordering proves.
 */
#include <stdio.h>
#include <stdint.h>
#include <string.h>

#define E1000_VFMAILBOX_SIZE		16
#define E1000_VT_MSGINFO_SHIFT		16
#define E1000_VF_SET_MULTICAST		0x03
#define E1000_VF_SET_MULTICAST_OVERFLOW	(0x80u << E1000_VT_MSGINFO_SHIFT)

static void emulate(unsigned count, int fixed, uint32_t msgbuf[], int init[])
{
	unsigned i, n = count;
	uint16_t *hash_list = (uint16_t *)&msgbuf[1];

	memset(msgbuf, 0, sizeof(uint32_t) * E1000_VFMAILBOX_SIZE);
	memset(init, 0, sizeof(int) * 4 * E1000_VFMAILBOX_SIZE);

	if (!fixed) {
		/* current DragonFly (e1000_vf.c:421-427) */
		if (n > 30) {
			msgbuf[0] |= E1000_VF_SET_MULTICAST_OVERFLOW;
			n = 30;
		}
		msgbuf[0] = E1000_VF_SET_MULTICAST;	/* kills the flag */
	} else {
		/* fixed (upstream FreeBSD ordering) */
		if (n > 30) {
			msgbuf[0] = E1000_VF_SET_MULTICAST |
				    E1000_VF_SET_MULTICAST_OVERFLOW;
			n = 30;
		} else {
			msgbuf[0] = E1000_VF_SET_MULTICAST;
		}
	}
	msgbuf[0] |= n << E1000_VT_MSGINFO_SHIFT;
	for (i = 0; i < 4; i++)
		init[i] = 1;

	/* hash loop writes hash_list[0..n-1] == msgbuf bytes 4..4+2n-1 */
	for (i = 0; i < n; i++) {
		hash_list[i] = 0x0abc;
		init[4 + 2 * i] = 1;
		init[4 + 2 * i + 1] = 1;
	}
}

int main(void)
{
	uint32_t msgbuf[E1000_VFMAILBOX_SIZE];
	int init[4 * E1000_VFMAILBOX_SIZE];
	unsigned counts[] = { 5, 31, 128 };
	unsigned c;
	int uninit_bytes, i, fixed;

	printf("E1000_VF_SET_MULTICAST_OVERFLOW = 0x%08x\n\n",
	    E1000_VF_SET_MULTICAST_OVERFLOW);
	for (fixed = 0; fixed <= 1; fixed++) {
		printf("=== %s ordering ===\n",
		    fixed ? "FIXED (upstream)" : "CURRENT DragonFly");
		for (c = 0; c < sizeof(counts) / sizeof(counts[0]); c++) {
			emulate(counts[c], fixed, msgbuf, init);
			uninit_bytes = 0;
			for (i = 0; i < 4 * E1000_VFMAILBOX_SIZE; i++)
				if (!init[i])
					uninit_bytes++;
			printf("  mc_addr_count=%3u: PF-visible msgbuf[0]=0x%08x "
			    "(OVERFLOW flag %s), uninit stack bytes sent to PF: "
			    "%d of 60\n",
			    counts[c], msgbuf[0],
			    (msgbuf[0] & E1000_VF_SET_MULTICAST_OVERFLOW) ?
			    "SET" : "LOST",
			    uninit_bytes);
		}
	}
	return 0;
}