/*
 * DF-4611 offset-math prover — neomagic nm_init() trusts card-provided
 * buftop (neomagic.c:576-588).
 *
 * Reproduces, in portable userland, the exact arithmetic nm_init() runs
 * after the card-memory override
 *
 *   ofs    = buftop - 0x0400;
 *   buftop-= 0x1400;
 *   if (signature@ofs == NM_SIGNATURE && (i = read@ofs+4) != 0/0xffffffff)
 *       buftop = i;                        <- unvalidated card value
 *   cbuf  = buftop - 0x5000;
 *   rbuf  = cbuf  - 0x4000;
 *   pbuf  = rbuf  - 0x4000;
 *   acbuf = pbuf  - 0x3158*4;
 *
 * and prints, for hostile buftop values, the offsets later fed to
 * bus_space_write (nm_loadcoeff: sc->cbuf + i, i up to 0x4fff) and to
 * sndbuf_setup (rman_get_virtual(sc->buf) + chnbuf) -- i.e. how far
 * BELOW the BAR mapping kernel writes would land.
 *
 * The kernel-side trigger needs real NM256 hardware whose buffer-memory
 * signature block returns a crafted `i`; the audit guest has no such
 * function (QEMU 7.2 has no NM256 model), so this prover documents the
 * corruption arithmetic instead of the kernel write itself.
 */
#include <stdio.h>
#include <stdint.h>

int
main(void)
{
	static const uint32_t hostile[] = {
		0x00000100,	/* absurdly small */
		0x00000fff,	/* below minimum needed */
		0x0000beef,	/* garbage */
		0x0001b95f,	/* one byte below the true minimum 0x1b960 */
		0x00100000,	/* 1MB - fine on paper, truncated card */
	};
	uint32_t sane[] = { 0x400000, 0x600000 }; /* ZX legit values */
	size_t k;

	printf("%-10s %-10s %-10s %-10s %-10s  %s\n",
	    "buftop", "cbuf", "rbuf", "pbuf", "acbuf", "verdict");
	for (k = 0; k < sizeof(hostile) / sizeof(hostile[0]); k++) {
		uint32_t bt = hostile[k] - 0x1400;
		uint32_t cbuf = bt - 0x5000, rbuf = cbuf - 0x4000,
		    pbuf = rbuf - 0x4000, acbuf = pbuf - 0x3158 * 4;
		int wraps = (cbuf >> 31) | (rbuf >> 31) | (pbuf >> 31) |
		    (acbuf >> 31);
		printf("%08x   %08x   %08x   %08x   %08x  %s\n",
		    bt, cbuf, rbuf, pbuf, acbuf,
		    wraps ? "WRAPS -> ~4G OOB bus_space offset" :
		    "below 0x1b960 -> overlaps regs/coeff areas");
	}
	for (k = 0; k < sizeof(sane) / sizeof(sane[0]); k++) {
		uint32_t bt = sane[k] - 0x1400;
		uint32_t cbuf = bt - 0x5000, rbuf = cbuf - 0x4000,
		    pbuf = rbuf - 0x4000, acbuf = pbuf - 0x3158 * 4;
		printf("%08x   %08x   %08x   %08x   %08x  %s\n",
		    bt, cbuf, rbuf, pbuf, acbuf, "in range (legit)");
	}
	printf("\nminimum sane buftop = 0x1400+0x5000+2*0x4000+0x3158*4 = 0x1b960\n");
	return 0;
}
