/*
 * df4942_harness.c — unit-level proof of the hw_translate_dce80 decode defects
 * (DragonFlyBSD pass-2 audit, files:
 *   sys/dev/drm/amd/display/dc/gpio/dce80/hw_translate_dce80.c
 *   sys/dev/drm/amd/display/dc/gpio/dce120/hw_translate_dce120.c)
 *
 * offset_to_id() / id_to_offset() / index_from_vector() below are VERBATIM
 * copies from hw_translate_dce80.c (lines 44-400) with exactly one
 * substitution: BREAK_TO_DEBUGGER() is mapped to a printf so the failure
 * markers are visible. All register constants are the real values from:
 *   sys/dev/drm/amd/include/asic_reg/dce/dce_8_0_d.h
 *   sys/dev/drm/amd/include/asic_reg/dce/dce_8_0_sh_mask.h
 *   sys/dev/drm/amd/include/asic_reg/smu/smu_7_0_1_d.h   (mmGPIOPAD_A)
 * and the enums are the real values from:
 *   sys/dev/drm/amd/display/include/gpio_types.h
 *
 * This proves the FUNCTION CONTRACT violations of the translate layer
 * (the trust boundary between VBIOS-derived register offsets and the
 * engine array indices). Kernel-level impact additionally requires an AMD
 * ASIC with a crafted VBIOS image (GPIO pin LUT / GPIO_I2C record), which
 * the QEMU guest does not have — see VERDICT.md.
 */
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#define BREAK_TO_DEBUGGER() printf("    [BREAK_TO_DEBUGGER hit]\n")

/* ---- gpio_types.h (verbatim values) ---- */
enum gpio_id {
	GPIO_ID_UNKNOWN = (-1),
	GPIO_ID_DDC_DATA,
	GPIO_ID_DDC_CLOCK,
	GPIO_ID_GENERIC,
	GPIO_ID_HPD,
	GPIO_ID_GPIO_PAD,
	GPIO_ID_VIP_PAD,
	GPIO_ID_SYNC,
	GPIO_ID_GSL,
	GPIO_ID_COUNT,
	GPIO_ID_MIN = GPIO_ID_DDC_DATA,
	GPIO_ID_MAX = GPIO_ID_GSL
};
#define GPIO_ENUM_UNKNOWN 32

struct gpio_pin_info {
	uint32_t offset;
	uint32_t offset_y;
	uint32_t offset_en;
	uint32_t offset_mask;
	uint32_t mask;
	uint32_t mask_y;
	uint32_t mask_en;
	uint32_t mask_mask;
};

enum gpio_generic {
	GPIO_GENERIC_UNKNOWN = (-1),
	GPIO_GENERIC_A, GPIO_GENERIC_B, GPIO_GENERIC_C, GPIO_GENERIC_D,
	GPIO_GENERIC_E, GPIO_GENERIC_F, GPIO_GENERIC_G,
	GPIO_GENERIC_COUNT,
};
enum gpio_hpd {
	GPIO_HPD_UNKNOWN = (-1),
	GPIO_HPD_1, GPIO_HPD_2, GPIO_HPD_3,
	GPIO_HPD_4, GPIO_HPD_5, GPIO_HPD_6,
	GPIO_HPD_COUNT,
};
enum gpio_gpio_pad {
	GPIO_GPIO_PAD_UNKNOWN = (-1),
	GPIO_GPIO_PAD_0, GPIO_GPIO_PAD_1, GPIO_GPIO_PAD_2, GPIO_GPIO_PAD_3,
	GPIO_GPIO_PAD_4, GPIO_GPIO_PAD_5, GPIO_GPIO_PAD_6, GPIO_GPIO_PAD_7,
	GPIO_GPIO_PAD_8, GPIO_GPIO_PAD_9, GPIO_GPIO_PAD_10, GPIO_GPIO_PAD_11,
	GPIO_GPIO_PAD_12, GPIO_GPIO_PAD_13, GPIO_GPIO_PAD_14, GPIO_GPIO_PAD_15,
	GPIO_GPIO_PAD_16, GPIO_GPIO_PAD_17, GPIO_GPIO_PAD_18, GPIO_GPIO_PAD_19,
	GPIO_GPIO_PAD_20, GPIO_GPIO_PAD_21, GPIO_GPIO_PAD_22, GPIO_GPIO_PAD_23,
	GPIO_GPIO_PAD_24, GPIO_GPIO_PAD_25, GPIO_GPIO_PAD_26, GPIO_GPIO_PAD_27,
	GPIO_GPIO_PAD_28, GPIO_GPIO_PAD_29, GPIO_GPIO_PAD_30,
	GPIO_GPIO_PAD_COUNT,
	GPIO_GPIO_PAD_MAX = GPIO_GPIO_PAD_30
};
enum gpio_sync {
	GPIO_SYNC_UNKNOWN = (-1),
	GPIO_SYNC_HSYNC_A, GPIO_SYNC_VSYNC_A,
	GPIO_SYNC_HSYNC_B, GPIO_SYNC_VSYNC_B,
	GPIO_SYNC_COUNT,
};
enum gpio_gsl {
	GPIO_GSL_UNKNOWN = (-1),
	GPIO_GSL_GENLOCK_CLOCK, GPIO_GSL_GENLOCK_VSYNC,
	GPIO_GSL_SWAPLOCK_A, GPIO_GSL_SWAPLOCK_B,
	GPIO_GSL_COUNT,
};
enum gpio_ddc_line {
	GPIO_DDC_LINE_UNKNOWN = (-1),
	GPIO_DDC_LINE_DDC1, GPIO_DDC_LINE_DDC2, GPIO_DDC_LINE_DDC3,
	GPIO_DDC_LINE_DDC4, GPIO_DDC_LINE_DDC5, GPIO_DDC_LINE_DDC6,
	GPIO_DDC_LINE_DDC_VGA,
	GPIO_DDC_LINE_VIP_PAD,
	GPIO_DDC_LINE_I2C_PAD = GPIO_DDC_LINE_VIP_PAD,
	GPIO_DDC_LINE_COUNT,
};

/* ---- dce_8_0_d.h / smu_7_0_1_d.h (verbatim values) ---- */
#define mmDC_GPIO_GENERIC_A       0x1945
#define mmDC_GPIO_DDC1_A          0x194d
#define mmDC_GPIO_DDC2_A          0x1951
#define mmDC_GPIO_DDC3_A          0x1955
#define mmDC_GPIO_DDC4_A          0x1959
#define mmDC_GPIO_DDC5_A          0x195d
#define mmDC_GPIO_DDC6_A          0x1961
#define mmDC_GPIO_SYNCA_A         0x1965
#define mmDC_GPIO_GENLK_A         0x1969
#define mmDC_GPIO_HPD_A           0x196d
#define mmDC_GPIO_DDCVGA_A        0x1971
#define mmDC_GPIO_I2CPAD_A        0x1975
#define mmDC_GPIO_PWRSEQ_A        0x1941
#define mmDC_GPIO_PAD_STRENGTH_1  0x1978
#define mmDC_GPIO_PAD_STRENGTH_2  0x1979
#define mmDC_GPIO_DEBUG           0x1904
#define mmGPIOPAD_A               0x183

/* ---- dce_8_0_sh_mask.h (verbatim values) ---- */
#define DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK 0x1
#define DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK 0x100
#define DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK 0x10000
#define DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK 0x100000
#define DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK 0x200000
#define DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK 0x400000
#define DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK 0x800000
#define DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK 0x1
#define DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK 0x100
#define DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK 0x10000
#define DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK 0x1000000
#define DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK 0x4000000
#define DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK 0x10000000
#define DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK 0x1
#define DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK 0x100
#define DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK 0x1
#define DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK 0x100
#define DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK 0x10000
#define DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK 0x1000000
#define DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK 0x100
#define DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK 0x1

/* ================= VERBATIM from hw_translate_dce80.c:44-61 ================= */
static uint32_t index_from_vector(
	uint32_t vector)
{
	uint32_t result = 0;
	uint32_t mask = 1;

	do {
		if (vector == mask)
			return result;

		++result;
		mask <<= 1;
	} while (mask);

	BREAK_TO_DEBUGGER();

	return GPIO_ENUM_UNKNOWN;
}

/* ============ VERBATIM from hw_translate_dce80.c:63-208 ============ */
static bool offset_to_id(
	uint32_t offset,
	uint32_t mask,
	enum gpio_id *id,
	uint32_t *en)
{
	switch (offset) {
	/* GENERIC */
	case mmDC_GPIO_GENERIC_A:
		*id = GPIO_ID_GENERIC;
		switch (mask) {
		case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK:
			*en = GPIO_GENERIC_A;
			return true;
		case DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK:
			*en = GPIO_GENERIC_B;
			return true;
		case DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK:
			*en = GPIO_GENERIC_C;
			return true;
		case DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK:
			*en = GPIO_GENERIC_D;
			return true;
		case DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK:
			*en = GPIO_GENERIC_E;
			return true;
		case DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK:
			*en = GPIO_GENERIC_F;
			return true;
		case DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK:
			*en = GPIO_GENERIC_G;
			return true;
		default:
			BREAK_TO_DEBUGGER();
			return false;
		}
	break;
	/* HPD */
	case mmDC_GPIO_HPD_A:
		*id = GPIO_ID_HPD;
		switch (mask) {
		case DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK:
			*en = GPIO_HPD_1;
			return true;
		case DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK:
			*en = GPIO_HPD_2;
			return true;
		case DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK:
			*en = GPIO_HPD_3;
			return true;
		case DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK:
			*en = GPIO_HPD_4;
			return true;
		case DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK:
			*en = GPIO_HPD_5;
			return true;
		case DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK:
			*en = GPIO_HPD_6;
			return true;
		default:
			BREAK_TO_DEBUGGER();
			return false;
		}
	break;
	/* SYNCA */
	case mmDC_GPIO_SYNCA_A:
		*id = GPIO_ID_SYNC;
		switch (mask) {
		case DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK:
			*en = GPIO_SYNC_HSYNC_A;
			return true;
		case DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK:
			*en = GPIO_SYNC_VSYNC_A;
			return true;
		default:
			BREAK_TO_DEBUGGER();
			return false;
		}
	break;
	/* mmDC_GPIO_GENLK_MASK */
	case mmDC_GPIO_GENLK_A:
		*id = GPIO_ID_GSL;
		switch (mask) {
		case DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK:
			*en = GPIO_GSL_GENLOCK_CLOCK;
			return true;
		case DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK:
			*en = GPIO_GSL_GENLOCK_VSYNC;
			return true;
		case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK:
			*en = GPIO_GSL_SWAPLOCK_A;
			return true;
		case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK:
			*en = GPIO_GSL_SWAPLOCK_B;
			return true;
		default:
			BREAK_TO_DEBUGGER();
			return false;
		}
	break;
	/* GPIOPAD */
	case mmGPIOPAD_A:
		*id = GPIO_ID_GPIO_PAD;
		*en = index_from_vector(mask);
		return (*en <= GPIO_GPIO_PAD_MAX);
	/* DDC */
	/* we don't care about the GPIO_ID for DDC
	 * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK
	 * directly in the create method */
	case mmDC_GPIO_DDC1_A:
		*en = GPIO_DDC_LINE_DDC1;
		return true;
	case mmDC_GPIO_DDC2_A:
		*en = GPIO_DDC_LINE_DDC2;
		return true;
	case mmDC_GPIO_DDC3_A:
		*en = GPIO_DDC_LINE_DDC3;
		return true;
	case mmDC_GPIO_DDC4_A:
		*en = GPIO_DDC_LINE_DDC4;
		return true;
	case mmDC_GPIO_DDC5_A:
		*en = GPIO_DDC_LINE_DDC5;
		return true;
	case mmDC_GPIO_DDC6_A:
		*en = GPIO_DDC_LINE_DDC6;
		return true;
	case mmDC_GPIO_DDCVGA_A:
		*en = GPIO_DDC_LINE_DDC_VGA;
		return true;
	/* GPIO_I2CPAD */
	case mmDC_GPIO_I2CPAD_A:
		*en = GPIO_DDC_LINE_I2C_PAD;
		return true;
	/* Not implemented */
	case mmDC_GPIO_PWRSEQ_A:
	case mmDC_GPIO_PAD_STRENGTH_1:
	case mmDC_GPIO_PAD_STRENGTH_2:
	case mmDC_GPIO_DEBUG:
		return false;
	/* UNEXPECTED */
	default:
		BREAK_TO_DEBUGGER();
		return false;
	}
}

/* ============ VERBATIM from hw_translate_dce80.c:210-400 ============ */
static bool id_to_offset(
	enum gpio_id id,
	uint32_t en,
	struct gpio_pin_info *info)
{
	bool result = true;

	switch (id) {
	case GPIO_ID_DDC_DATA:
		info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK;
		switch (en) {
		case GPIO_DDC_LINE_DDC1:
			info->offset = mmDC_GPIO_DDC1_A;
		break;
		case GPIO_DDC_LINE_DDC2:
			info->offset = mmDC_GPIO_DDC2_A;
		break;
		case GPIO_DDC_LINE_DDC3:
			info->offset = mmDC_GPIO_DDC3_A;
		break;
		case GPIO_DDC_LINE_DDC4:
			info->offset = mmDC_GPIO_DDC4_A;
		break;
		case GPIO_DDC_LINE_DDC5:
			info->offset = mmDC_GPIO_DDC5_A;
		break;
		case GPIO_DDC_LINE_DDC6:
			info->offset = mmDC_GPIO_DDC6_A;
		break;
		case GPIO_DDC_LINE_DDC_VGA:
			info->offset = mmDC_GPIO_DDCVGA_A;
		break;
		case GPIO_DDC_LINE_I2C_PAD:
			info->offset = mmDC_GPIO_I2CPAD_A;
		break;
		default:
			BREAK_TO_DEBUGGER();
			result = false;
		}
	break;
	case GPIO_ID_DDC_CLOCK:
		info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK;
		switch (en) {
		case GPIO_DDC_LINE_DDC1:
			info->offset = mmDC_GPIO_DDC1_A;
		break;
		case GPIO_DDC_LINE_DDC2:
			info->offset = mmDC_GPIO_DDC2_A;
		break;
		case GPIO_DDC_LINE_DDC3:
			info->offset = mmDC_GPIO_DDC3_A;
		break;
		case GPIO_DDC_LINE_DDC4:
			info->offset = mmDC_GPIO_DDC4_A;
		break;
		case GPIO_DDC_LINE_DDC5:
			info->offset = mmDC_GPIO_DDC5_A;
		break;
		case GPIO_DDC_LINE_DDC6:
			info->offset = mmDC_GPIO_DDC6_A;
		break;
		case GPIO_DDC_LINE_DDC_VGA:
			info->offset = mmDC_GPIO_DDCVGA_A;
		break;
		case GPIO_DDC_LINE_I2C_PAD:
			info->offset = mmDC_GPIO_I2CPAD_A;
		break;
		default:
			BREAK_TO_DEBUGGER();
			result = false;
		}
	break;
	case GPIO_ID_GENERIC:
		info->offset = mmDC_GPIO_GENERIC_A;
		switch (en) {
		case GPIO_GENERIC_A:
			info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK;
		break;
		case GPIO_GENERIC_B:
			info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK;
		break;
		case GPIO_GENERIC_C:
			info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK;
		break;
		case GPIO_GENERIC_D:
			info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK;
		break;
		case GPIO_GENERIC_E:
			info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK;
		break;
		case GPIO_GENERIC_F:
			info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK;
		break;
		case GPIO_GENERIC_G:
			info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK;
		break;
		default:
			BREAK_TO_DEBUGGER();
			result = false;
		}
	break;
	case GPIO_ID_HPD:
		info->offset = mmDC_GPIO_HPD_A;
		switch (en) {
		case GPIO_HPD_1:
			info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK;
		break;
		case GPIO_HPD_2:
			info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK;
		break;
		case GPIO_HPD_3:
			info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK;
		break;
		case GPIO_HPD_4:
			info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK;
		break;
		case GPIO_HPD_5:
			info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK;
		break;
		case GPIO_HPD_6:
			info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK;
		break;
		default:
			BREAK_TO_DEBUGGER();
			result = false;
		}
	break;
	case GPIO_ID_SYNC:
		switch (en) {
		case GPIO_SYNC_HSYNC_A:
			info->offset = mmDC_GPIO_SYNCA_A;
			info->mask = DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK;
		break;
		case GPIO_SYNC_VSYNC_A:
			info->offset = mmDC_GPIO_SYNCA_A;
			info->mask = DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK;
		break;
		case GPIO_SYNC_HSYNC_B:
		case GPIO_SYNC_VSYNC_B:
		default:
			BREAK_TO_DEBUGGER();
			result = false;
		}
	break;
	case GPIO_ID_GSL:
		switch (en) {
		case GPIO_GSL_GENLOCK_CLOCK:
			info->offset = mmDC_GPIO_GENLK_A;
			info->mask = DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK;
		break;
		case GPIO_GSL_GENLOCK_VSYNC:
			info->offset = mmDC_GPIO_GENLK_A;
			info->mask =
				DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK;
		break;
		case GPIO_GSL_SWAPLOCK_A:
			info->offset = mmDC_GPIO_GENLK_A;
			info->mask = DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK;
		break;
		case GPIO_GSL_SWAPLOCK_B:
			info->offset = mmDC_GPIO_GENLK_A;
			info->mask = DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK;
		break;
		default:
			BREAK_TO_DEBUGGER();
			result = false;
		}
	break;
	case GPIO_ID_GPIO_PAD:
		info->offset = mmGPIOPAD_A;
		info->mask = (1 << en);
		result = (info->mask <= GPIO_GPIO_PAD_MAX);
	break;
	case GPIO_ID_VIP_PAD:
	default:
		BREAK_TO_DEBUGGER();
		result = false;
	}

	if (result) {
		info->offset_y = info->offset + 2;
		info->offset_en = info->offset + 1;
		info->offset_mask = info->offset - 1;

		info->mask_y = info->mask;
		info->mask_en = info->mask;
		info->mask_mask = info->mask;
	}

	return result;
}

/* ============================== tests ============================== */
#define HPD_REGS_SIZE      6   /* hw_factory_dce80.c hpd_regs[]          */
#define DDC_REGS_SIZE      8   /* hw_factory_dce80.c ddc_data_regs[]    */

static const char *idname(enum gpio_id id)
{
	switch (id) {
	case GPIO_ID_DDC_DATA: return "GPIO_ID_DDC_DATA(0)";
	case GPIO_ID_DDC_CLOCK: return "GPIO_ID_DDC_CLOCK(1)";
	case GPIO_ID_GENERIC: return "GPIO_ID_GENERIC(2)";
	case GPIO_ID_HPD: return "GPIO_ID_HPD(3)";
	case GPIO_ID_GPIO_PAD: return "GPIO_ID_GPIO_PAD(4)";
	case GPIO_ID_VIP_PAD: return "GPIO_ID_VIP_PAD(5)";
	case GPIO_ID_SYNC: return "GPIO_ID_SYNC(6)";
	case GPIO_ID_GSL: return "GPIO_ID_GSL(7)";
	default: return "(other)";
	}
}

int main(void)
{
	int fails = 0;
	enum gpio_id id;
	uint32_t en;
	struct gpio_pin_info info;
	bool r;

	printf("== domain constants (gpio_types.h) ==\n");
	printf("GPIO_DDC_LINE_DDC1=%d DDC6=%d DDC_VGA=%d I2C_PAD(==VIP_PAD)=%d COUNT=%d\n",
		GPIO_DDC_LINE_DDC1, GPIO_DDC_LINE_DDC6,
		GPIO_DDC_LINE_DDC_VGA, GPIO_DDC_LINE_I2C_PAD,
		GPIO_DDC_LINE_COUNT);
	printf("GPIO_ENUM_UNKNOWN=%d GPIO_GPIO_PAD_MAX=%d\n",
		GPIO_ENUM_UNKNOWN, GPIO_GPIO_PAD_MAX);
	printf("consumer arrays: hpd_regs[%d] ddc_data_regs[%d] (hw_factory_dce80.c)\n",
		HPD_REGS_SIZE, DDC_REGS_SIZE);

	printf("\n== T1: DDC/VGA/I2CPAD offsets return success WITHOUT writing *id ==\n");
	printf("(dal_gpio_service_create_irq gpio_service.c:148 declares 'enum gpio_id id;' uninitialized)\n");
	id = (enum gpio_id)0x7B7B7B7B; /* stand-in for an uninitialized stack slot */
	r = offset_to_id(mmDC_GPIO_DDCVGA_A, 0x100, &id, &en);
	printf("offset_to_id(mmDC_GPIO_DDCVGA_A,0x100) = %s en=%d(id==%s)\n",
		r ? "true" : "false", en, idname(id));
	if (r && id == (enum gpio_id)0x7B7B7B7B) {
		printf("  -> BUG(DF-4943): success returned, *id NEVER WRITTEN;"
		       " consumer switches on uninitialized id\n");
		fails++;
	}
	id = (enum gpio_id)0x7B7B7B7B;
	r = offset_to_id(mmDC_GPIO_I2CPAD_A, 0x1, &id, &en);
	printf("offset_to_id(mmDC_GPIO_I2CPAD_A,0x1)  = %s en=%d(id==%s)\n",
		r ? "true" : "false", en, idname(id));
	if (r && id == (enum gpio_id)0x7B7B7B7B)
		fails++;
	id = (enum gpio_id)0x7B7B7B7B;
	r = offset_to_id(mmDC_GPIO_DDC1_A, 0x100, &id, &en);
	printf("offset_to_id(mmDC_GPIO_DDC1_A,0x100)  = %s en=%d(id==%s)\n",
		r ? "true" : "false", en, idname(id));
	if (r && id == (enum gpio_id)0x7B7B7B7B)
		fails++;

	printf("\n== T2: GPIOPAD offset succeeds with en up to 30 (DF-4942 producer) ==\n");
	printf("(dal_gpio_create_ddc ignores id and feeds en to ddc_data_regs[%d])\n", DDC_REGS_SIZE);
	id = (enum gpio_id)0x7B7B7B7B;
	r = offset_to_id(mmGPIOPAD_A, 1u << 20, &id, &en);
	printf("offset_to_id(mmGPIOPAD_A,1<<20) = %s id=%s en=%d\n",
		r ? "true" : "false", idname(id), en);
	if (r && id == GPIO_ID_GPIO_PAD && en >= DDC_REGS_SIZE) {
		printf("  -> BUG(DF-4942): success with en=%d >= %d entries:"
		       " define_ddc_registers reads ddc_data_regs[%d] OOB"
		       " (hw_factory_dce80.c:122), regs then drive MMIO\n",
		       en, DDC_REGS_SIZE, en);
		fails++;
	}
	/* boundary: en == 7 (last valid ddc index) via shift 7 */
	r = offset_to_id(mmGPIOPAD_A, 1u << 7, &id, &en);
	printf("offset_to_id(mmGPIOPAD_A,1<<7)  = %s en=%d (in-bounds, no OOB)\n",
		r ? "true" : "false", en);

	printf("\n== T3 (negative): GPIOPAD en bound inside offset_to_id is sound ==\n");
	r = offset_to_id(mmGPIOPAD_A, 1u << 31, &id, &en);
	printf("offset_to_id(mmGPIOPAD_A,1<<31) = %s en=%d (31>30 rejected: OK)\n",
		r ? "true" : "false", en);
	if (r) fails++;
	r = offset_to_id(mmGPIOPAD_A, 0x3, &id, &en);
	printf("offset_to_id(mmGPIOPAD_A,0x3)   = %s en=%d (multi-bit->UNKNOWN=32 rejected: OK)\n",
		r ? "true" : "false", en);
	if (r) fails++;
	r = offset_to_id(mmGPIOPAD_A, 0x0, &id, &en);
	printf("offset_to_id(mmGPIOPAD_A,0x0)   = %s en=%d (zero->UNKNOWN=32 rejected: OK)\n",
		r ? "true" : "false", en);
	if (r) fails++;

	printf("\n== T4: id_to_offset GPIO_PAD compares MASK vs INDEX (DF-4944) ==\n");
	memset(&info, 0xCC, sizeof(info));
	r = id_to_offset(GPIO_ID_GPIO_PAD, 5, &info);
	printf("id_to_offset(GPIO_PAD,en=5)  = %s mask=0x%x (pad 5 is VALID per enum but rejected: 1<<5=32 > 30)\n",
		r ? "true" : "false", info.mask);
	r = id_to_offset(GPIO_ID_GPIO_PAD, 30, &info);
	printf("id_to_offset(GPIO_PAD,en=30) = %s mask=0x%x (pad 30 VALID, rejected)\n",
		r ? "true" : "false", info.mask);
	r = id_to_offset(GPIO_ID_GPIO_PAD, 32, &info);
	printf("id_to_offset(GPIO_PAD,en=32) = %s mask=0x%x (en=32 is INVALID;"
	       " UB shift 1<<32 -> mask=1 <= 30 -> ACCEPTED with wrong mask)\n",
		r ? "true" : "false", info.mask);
	if (r && info.mask == 0x1) {
		printf("  -> BUG(DF-4944): invalid en=32 accepted via UB shift on this build\n");
		fails++;
	}
	r = id_to_offset(GPIO_ID_GPIO_PAD, 64, &info);
	printf("id_to_offset(GPIO_PAD,en=64) = %s mask=0x%x (invalid, also accepted via UB)\n",
		r ? "true" : "false", info.mask);

	printf("\n== T5 (negative): HPD id_to_offset rejects en>=6 ==\n");
	r = id_to_offset(GPIO_ID_HPD, GPIO_HPD_6, &info);
	printf("id_to_offset(HPD,en=5) = %s (OK)\n", r ? "true" : "false");
	if (!r) fails++;
	r = id_to_offset(GPIO_ID_HPD, 6, &info);
	printf("id_to_offset(HPD,en=6) = %s (rejected: OK — only the uninit-id path can smuggle en>=6 into hpd_regs)\n",
		r ? "true" : "false");

	printf("\n%d contract-violation reproductions (T1/T2/T4 classes)\n", fails);
	return (fails > 0) ? 0 : 1; /* 0 exit = bugs demonstrated */
}
