/*
 * layout.c -- userland proof of the struct i915_params layout used by
 * DF-5135: bool params are 1 byte, sit at the tail of the struct, and a
 * 4-byte int store into one of them lands in the following members.
 */
#include <stdio.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>

struct i915_params {
	char *vbt_firmware;
	int modeset, lvds_channel_mode, panel_use_ssc, vbt_sdvo_panel_type;
	int enable_dc, enable_fbc, enable_ppgtt, enable_psr, disable_power_well;
	int enable_ips, invert_brightness, enable_guc, guc_log_level;
	char *guc_firmware_path, *huc_firmware_path, *dmc_firmware_path;
	int mmio_debug, edp_vswing, reset;
	unsigned int inject_load_failure;
	bool alpha_support, enable_hangcheck, fastboot, prefault_disable,
	    load_detect_test, force_reset_modeset_test, error_capture,
	    disable_display, verbose_state_checks, nuclear_pageflip,
	    enable_dp_mst, enable_dpcd_backlight, enable_gvt;
};

int
main(void)
{
	struct i915_params p;

	printf("sizeof(bool)=%zu sizeof(struct i915_params)=%zu\n",
		sizeof(bool), sizeof(struct i915_params));
	printf("offsets: error_capture=%zu disable_display=%zu "
		"verbose_state_checks=%zu nuclear_pageflip=%zu "
		"enable_dp_mst=%zu enable_gvt=%zu(last)\n",
		offsetof(struct i915_params, error_capture),
		offsetof(struct i915_params, disable_display),
		offsetof(struct i915_params, verbose_state_checks),
		offsetof(struct i915_params, nuclear_pageflip),
		offsetof(struct i915_params, enable_dp_mst),
		offsetof(struct i915_params, enable_gvt));

	/* kenv i915.error_capture=1 => kgetenv_int() does *(int*)&p.error_capture = 1 */
	memset(&p, 0xAA, sizeof(p));
	*(int *)((char *)&p + offsetof(struct i915_params, error_capture)) = 1;
	printf("after 'i915.error_capture=1': error_capture=%d "
		"disable_display=%d verbose_state_checks=%d nuclear_pageflip=%d "
		"(0xAA bytes overwritten to 0 => silent corruption)\n",
		p.error_capture, p.disable_display, p.verbose_state_checks,
		p.nuclear_pageflip);

	*(int *)((char *)&p + offsetof(struct i915_params, enable_hangcheck)) = 1;
	printf("after 'i915.enable_hangcheck=1': enable_hangcheck=%d "
		"fastboot=%d prefault_disable=%d load_detect_test=%d\n",
		p.enable_hangcheck, p.fastboot, p.prefault_disable,
		p.load_detect_test);

	/* last member: store stays inside the struct's tail padding */
	memset(&p, 0, sizeof(p));
	*(int *)((char *)&p + offsetof(struct i915_params, enable_gvt)) = 1;
	printf("after 'i915.enable_gvt=1' (last member): "
		"4-byte store [112..115] within sizeof=%zu => no OOB write "
		"past the object\n", sizeof(struct i915_params));
	return 0;
}
