⬢ DragonFlyBSD Kernel Audit
DF-2214 / rig_tail.c
← back to finding ↓ download raw
/*
 * DF-2214 verbatim-code rig - TAIL
 * Matrix driver + module glue. Runs the UNMODIFIED production function
 * (rv770_copy_dma, concatenated above from tree lines 42-94) and the FIXED
 * variant (rv770_copy_dma_fixed, fix.diff applied + renamed) over the exact
 * input domain that flips the claimed bug and prints, per case:
 *   - the ndw the function tried to reserve  (== num_loops*5+8)
 *   - every DMA_PACKET_COPY header emitted into the ring (count, chunk sizes)
 *   - whether a success fence was emitted
 *   - bytes the DMA engine was actually told to move vs bytes requested
 *   - canary integrity around the ring buffer (host-memory-safety check)
 */
#define CANARY_ZONE	4096
#define CANARY_WORD	0xCAFEBABEu
#define RIG_SRC_BASE	0x123456789ABCLL	/* nontrivial 44-bit GPU addrs */
#define RIG_DST_BASE	0xFEDCBA987654LL

struct rig_case {
	unsigned	pages;
	unsigned	ring_bytes;	/* ring buffer geometry */
	const char	*ring_tag;
};

static const struct rig_case rig_cases[] = {
	/* --- big ring (4 MiB, plenty for every reservation below) --- */
	{ 0x000FFFFFu, 0x400000u, "big4M" },	/* 2^20-1: last non-wrapping */
	{ 0x00100000u, 0x400000u, "big4M" },	/* 2^20  : exact wrap to 0   */
	{ 0x00100001u, 0x400000u, "big4M" },	/* 2^20+1: wraps to 4 KiB    */
	{ 0x00100800u, 0x400000u, "big4M" },	/* 2^20+2048: wraps to 8 MiB */
	{ 0xC0000000u, 0x400000u, "big4M" },	/* 12 TiB request: total loss*/
	/* --- realistic rv770 DMA ring: 64 KiB (rv770.c:1968) --- */
	{ 0x00008000u, 0x010000u, "real64K" },	/* 128 MiB move: fits, control */
	{ 0x000FFFFFu, 0x010000u, "real64K" },	/* 4 GiB-4K: loud ENOMEM (fixed/correct) vs silent no-op (buggy) */
	{ 0x00100000u, 0x010000u, "real64K" },	/* 4 GiB: the money shot */
};

static int rig_canary_ok(u32 *buf, unsigned ring_bytes)
{
	unsigned i, words = CANARY_ZONE / 4;

	for (i = 0; i < words; i++)
		if (buf[i] != CANARY_WORD ||
		    buf[words + ring_bytes / 4 + i] != CANARY_WORD)
			return 0;
	return 1;
}

static void run_case(int fixed, const struct rig_case *c)
{
	static const struct radeon_asic asic = {
		.copy = { .dma_ring_index = R600_RING_TYPE_DMA_INDEX },
	};
	struct radeon_device rdev;
	struct reservation_object resv;
	struct radeon_fence *fence;
	u32 *buf;
	unsigned i;
	int err = 0;
	u64 requested, scheduled;
	int canary;
	int is_err_ptr;

	memset(&rdev, 0, sizeof(rdev));
	rdev.asic = &asic;
	lockinit(&rdev.ring_lock, "df2214lk", 0, 0);

	/* ring geometry per radeon_ring_init (radeon_ring.c:404-411) */
	{
		struct radeon_ring *ring = &rdev.ring[R600_RING_TYPE_DMA_INDEX];
		ring->idx = R600_RING_TYPE_DMA_INDEX;
		ring->ring_size = c->ring_bytes;
		ring->ptr_mask = (ring->ring_size / 4) - 1;
		ring->ring_free_dw = ring->ring_size / 4;
		ring->align_mask = 0;	/* boundary state: no commit padding */
		ring->ready = 1;
	}

	/* ring buffer bracketed by canary zones */
	buf = kmalloc(c->ring_bytes + 2 * CANARY_ZONE, M_TEMP,
		      M_WAITOK | M_ZERO);
	for (i = 0; i < CANARY_ZONE / 4; i++) {
		buf[i] = CANARY_WORD;
		buf[CANARY_ZONE / 4 + c->ring_bytes / 4 + i] = CANARY_WORD;
	}
	rdev.ring[R600_RING_TYPE_DMA_INDEX].ring = buf + CANARY_ZONE / 4;

	memset(&g_stats, 0, sizeof(g_stats));
	g_stats.min_chunk = 0xFFFFFFFFu;
	g_stats.max_chunk = 0;

	requested = (u64)c->pages << RADEON_GPU_PAGE_SHIFT;	/* rig-side 64-bit truth */

	if (fixed)
		fence = rv770_copy_dma_fixed(&rdev, RIG_SRC_BASE, RIG_DST_BASE,
					     c->pages, &resv);
	else
		fence = rv770_copy_dma(&rdev, RIG_SRC_BASE, RIG_DST_BASE,
				       c->pages, &resv);

	is_err_ptr = IS_ERR(fence);
	if (is_err_ptr)
		err = (int)(intptr_t)fence;

	scheduled = g_stats.sum_chunk_dw * 4;
	canary = rig_canary_ok(buf, c->ring_bytes);

	kprintf("DF2214 CASE variant=%s pages=0x%08x ring=%s(%u bytes)\n",
		fixed ? "FIXED" : "BASELINE", c->pages, c->ring_tag,
		c->ring_bytes);
	kprintf("DF2214   requested_bytes=%llu (0x%llx) attempted_ndw=%u lock_rc=%d\n",
		(unsigned long long)requested, (unsigned long long)requested,
		g_stats.attempted_ndw, g_stats.lock_rc);
	if (is_err_ptr) {
		kprintf("DF2214   ERR_PTR(%d): ring reservation refused, ZERO packets, NO fence - loud failure\n",
			err);
		kprintf("DF2214   VERDICT: ERR_PTR_FAIL\n");
	} else {
		unsigned loops = g_stats.attempted_ndw ?
			(g_stats.attempted_ndw - 8) / 5 : 0;
		kprintf("DF2214   num_loops=%u copy_packets=%u sum_chunk_dw=%llu max_chunk=%u min_chunk=%u ring_writes=%lu\n",
			loops, g_stats.copy_packets,
			(unsigned long long)g_stats.sum_chunk_dw,
			g_stats.max_chunk, g_stats.min_chunk, g_stats.writes);
		kprintf("DF2214   first_pkt=0x%08x (cmd=%u n=%u) first5=[%08x %08x %08x %08x %08x]\n",
			g_stats.first_pkt, (g_stats.first_pkt >> 28) & 0xF,
			g_stats.first_pkt & 0xFFFF,
			g_stats.first5[0], g_stats.first5[1],
			g_stats.first5[2], g_stats.first5[3],
			g_stats.first5[4]);
		kprintf("DF2214   scheduled_bytes=%llu (%lu.%04lu%% of request) fence_emitted=%d ring=%d seq=%llu\n",
			(unsigned long long)scheduled,
			(unsigned long)(scheduled * 100 / (requested ? requested : 1)),
			(unsigned long)((scheduled * 1000000 / (requested ? requested : 1)) % 10000),
			g_stats.fence_emits, g_stats.fence_ring,
			(unsigned long long)g_stats.fence_seq);
		kprintf("DF2214   integrity: canaries=%s count_dw_final=%d underruns=%d drm_errors=%d sync{c=%d r=%d g=%d f=%d} commit=%u\n",
			canary ? "INTACT" : "CLOBBERED",
			rdev.ring[R600_RING_TYPE_DMA_INDEX].count_dw,
			g_stats.underruns, g_stats.drm_errors,
			g_stats.sync_create, g_stats.sync_resv,
			g_stats.sync_rings, g_stats.sync_free,
			g_stats.committed);
		if (scheduled == requested)
			kprintf("DF2214   VERDICT: FULL_COPY\n");
		else if (g_stats.fence_emits)
			kprintf("DF2214   VERDICT: SILENT_TRUNCATION (fence says success, %llu of %llu bytes scheduled)\n",
				(unsigned long long)scheduled,
				(unsigned long long)requested);
		else
			kprintf("DF2214   VERDICT: INTERNAL_ERROR\n");
	}

	if (!is_err_ptr && fence)
		kfree(fence, M_TEMP);
	kfree(buf, M_TEMP);
	lockuninit(&rdev.ring_lock);
}

static void rig_matrix(void)
{
	size_t i;

	kprintf("DF2214 RIG start: kernel-resident verbatim rv770_copy_dma (baseline) + fix.diff variant\n");
	for (i = 0; i < sizeof(rig_cases) / sizeof(rig_cases[0]); i++)
		run_case(0, &rig_cases[i]);
	for (i = 0; i < sizeof(rig_cases) / sizeof(rig_cases[0]); i++)
		run_case(1, &rig_cases[i]);
	kprintf("DF2214 RIG done\n");
}

static int df2214_modevent(module_t mod, int type, void *arg)
{
	switch (type) {
	case MOD_LOAD:
		rig_matrix();
		return 0;
	case MOD_UNLOAD:
		return 0;
	default:
		return EOPNOTSUPP;
	}
}

static moduledata_t df2214_mod = {
	"df2214_rig",
	df2214_modevent,
	NULL
};

DECLARE_MODULE(df2214_rig, df2214_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
MODULE_VERSION(df2214_rig, 1);