/*
 * DF-4853 - machine-verify the struct geometry behind the evergreen_hdmi.c
 * enc_priv type confusion (DF-4635/DF-4828 family, evergreen sinks).
 * Structs verbatim from the audited tree:
 *   - struct drm_display_mode        sys/dev/drm/include/drm/drm_modes.h
 *   - struct radeon_encoder_lvds     sys/dev/drm/radeon/radeon_mode.h:381-397
 *   - struct radeon_encoder_atom_dig radeon_mode.h:427-445
 *   - struct radeon_afmt             radeon_mode.h:235-240
 */
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32;
struct list_head { struct list_head *next, *prev; };
typedef struct { int counter; } atomic_t;
struct kref { atomic_t refcount; };
struct drm_mode_object { uint32_t id; uint32_t type; struct drm_object_properties *properties; struct kref refcount; void (*free_cb)(struct kref *kref); };
#define DRM_DISPLAY_MODE_LEN 32
enum drm_mode_status { MODE_OK=0 };
enum hdmi_picture_aspect { HDMI_PICTURE_ASPECT_NONE };

/* verbatim from sys/dev/drm/include/drm/drm_modes.h */
struct drm_display_mode {
	struct list_head head;
	struct drm_mode_object base;
	char name[DRM_DISPLAY_MODE_LEN];
	enum drm_mode_status status;
	unsigned int type;
	int clock;
	int hdisplay; int hsync_start; int hsync_end; int htotal; int hskew;
	int vdisplay; int vsync_start; int vsync_end; int vtotal; int vscan;
	unsigned int flags;
	int width_mm; int height_mm;
	int crtc_clock; int crtc_hdisplay; int crtc_hblank_start; int crtc_hblank_end;
	int crtc_hsync_start; int crtc_hsync_end; int crtc_htotal; int crtc_hskew;
	int crtc_vdisplay; int crtc_vblank_start; int crtc_vblank_end; int crtc_vsync_start;
	int crtc_vsync_end; int crtc_vtotal;
	int *private;
	int private_flags;
	int vrefresh;
	int hsync;
	enum hdmi_picture_aspect picture_aspect_ratio;
	struct list_head export_head;
};

struct backlight_device;

/* verbatim from sys/dev/drm/radeon/radeon_mode.h:235-240 */
struct radeon_afmt {
	bool enabled;
	int offset;
	bool last_buffer_filled_status;
	int id;
};

/* verbatim from sys/dev/drm/radeon/radeon_mode.h:427-445 */
struct radeon_encoder_atom_dig {
	bool linkb;
	bool coherent_mode;
	int dig_encoder;
	uint32_t lcd_misc;
	uint16_t panel_pwr_delay;
	uint32_t lcd_ss_id;
	struct drm_display_mode native_mode;
	struct backlight_device *bl_dev;
	int dpms_mode;
	uint8_t backlight_level;
	int panel_mode;
	struct radeon_afmt *afmt;
	struct r600_audio_pin *pin;
	int active_mst_links;
};

/* verbatim from sys/dev/drm/radeon/radeon_mode.h:381-397 */
struct radeon_encoder_lvds {
	uint16_t panel_vcc_delay;
	uint8_t  panel_pwr_delay;
	uint8_t  panel_digon_delay;
	uint8_t  panel_blon_delay;
	uint16_t panel_ref_divider;
	uint8_t  panel_post_divider;
	uint16_t panel_fb_divider;
	bool     use_bios_dividers;
	uint32_t lvds_gen_cntl;
	struct drm_display_mode native_mode;
	struct backlight_device *bl_dev;
	int      dpms_mode;
	uint8_t  backlight_level;
};

int main(void)
{
	printf("sizeof(drm_display_mode)        = %zu\n", sizeof(struct drm_display_mode));
	printf("sizeof(radeon_encoder_lvds)     = %zu   <- enc_priv of LCD-carrying digital encoders\n",
		sizeof(struct radeon_encoder_lvds));
	printf("sizeof(radeon_encoder_atom_dig) = %zu   <- what evergreen_hdmi.c assumes\n",
		sizeof(struct radeon_encoder_atom_dig));
	printf("offsetof(dig, afmt)             = %zu   <- dig->afmt on lvds obj (evergreen_hdmi.c:431)\n",
		offsetof(struct radeon_encoder_atom_dig, afmt));
	printf("offsetof(afmt, enabled)         = %zu   <- wild write target (evergreen_hdmi.c:458)\n",
		offsetof(struct radeon_afmt, enabled));
	printf("offsetof(afmt, offset)          = %zu   <- wild read feeding MMIO (:438-455)\n",
		offsetof(struct radeon_afmt, offset));
	if (offsetof(struct radeon_encoder_atom_dig, afmt) >=
	    sizeof(struct radeon_encoder_lvds))
		printf("=> dig->afmt reads %zu byte(s) PAST the 280-byte lvds object "
			"(280 -> 288-byte slab chunk, ZERO slack) into the ADJACENT chunk\n",
			offsetof(struct radeon_encoder_atom_dig, afmt) -
			sizeof(struct radeon_encoder_lvds));
	return 0;
}
