/ util / intelvbttool / intelvbttool.c
intelvbttool.c
   1  /* SPDX-License-Identifier: GPL-2.0-only */
   2  
   3  #include <stdio.h>
   4  #include <sys/mman.h>
   5  #include <stdint.h>
   6  #include <string.h>
   7  #include <stdlib.h>
   8  #include <unistd.h>
   9  #include <sys/types.h>
  10  #include <sys/stat.h>
  11  #include <fcntl.h>
  12  #include <getopt.h>
  13  #include <errno.h>
  14  #include <stdarg.h>
  15  #include <commonlib/helpers.h>
  16  
  17  typedef uint8_t u8;
  18  typedef uint16_t u16;
  19  typedef uint32_t u32;
  20  
  21  #define DEF_ALLOC 1024
  22  
  23  typedef struct {
  24  	u16 signature;
  25  	u8 size;
  26  	u8 entrypoint[4];
  27  	u8 checksum;
  28  	u8 reserved[16];
  29  	u16 pcir_offset;
  30  	u16 vbt_offset;
  31  } __attribute__ ((packed)) optionrom_header_t;
  32  
  33  typedef struct {
  34  	u32 signature;
  35  	u16 vendor;
  36  	u16 device;
  37  	u16 reserved1;
  38  	u16 length;
  39  	u8  revision;
  40  	u8  classcode[3];
  41  	u16 imagelength;
  42  	u16 coderevision;
  43  	u8  codetype;
  44  	u8  indicator;
  45  	u16 reserved2;
  46  } __attribute__((packed)) optionrom_pcir_t;
  47  
  48  struct vbt_header {
  49  	u8 signature[20];
  50  	u16 version;
  51  	u16 header_size;
  52  	u16 vbt_size;
  53  	u8 vbt_checksum;
  54  	u8 reserved0;
  55  	u32 bdb_offset;
  56  	u32 aim_offset[4];
  57  } __attribute__ ((packed));
  58  
  59  struct bdb_header {
  60  	u8 signature[16];
  61  	u16 version;
  62  	u16 header_size;
  63  	u16 bdb_size;
  64  };
  65  
  66  struct vbios_data {
  67  	u8 type;		/* 0 == desktop, 1 == mobile */
  68  	u8 relstage;
  69  	u8 chipset;
  70  	u8 lvds_present:1;
  71  	u8 tv_present:1;
  72  	u8 rsvd2:6;		/* finish byte */
  73  	u8 rsvd3[4];
  74  	u8 signon[155];
  75  	u8 copyright[61];
  76  	u16 code_segment;
  77  	u8 dos_boot_mode;
  78  	u8 bandwidth_percent;
  79  	u8 rsvd4;		/* popup memory size */
  80  	u8 resize_pci_bios;
  81  	u8 rsvd5;		/* is crt already on ddc2 */
  82  } __attribute__ ((packed));
  83  
  84  struct bdb_general_features {
  85  	/* bits 1 */
  86  	u8 panel_fitting:2;
  87  	u8 flexaim:1;
  88  	u8 msg_enable:1;
  89  	u8 clear_screen:3;
  90  	u8 color_flip:1;
  91  
  92  	/* bits 2 */
  93  	u8 download_ext_vbt:1;
  94  	u8 enable_ssc:1;
  95  	u8 ssc_freq:1;
  96  	u8 enable_lfp_on_override:1;
  97  	u8 disable_ssc_ddt:1;
  98  	u8 rsvd7:1;
  99  	u8 display_clock_mode:1;
 100  	u8 rsvd8:1;		/* finish byte */
 101  
 102  	/* bits 3 */
 103  	u8 disable_smooth_vision:1;
 104  	u8 single_dvi:1;
 105  	u8 rsvd9:1;
 106  	u8 fdi_rx_polarity_inverted:1;
 107  	u8 rsvd10:4;		/* finish byte */
 108  
 109  	/* bits 4 */
 110  	u8 legacy_monitor_detect;
 111  
 112  	/* bits 5 */
 113  	u8 int_crt_support:1;
 114  	u8 int_tv_support:1;
 115  	u8 int_efp_support:1;
 116  	u8 dp_ssc_enb:1;	/* PCH attached eDP supports SSC */
 117  	u8 dp_ssc_freq:1;	/* SSC freq for PCH attached eDP */
 118  	u8 rsvd11:3;		/* finish byte */
 119  } __attribute__ ((packed));
 120  
 121  struct common_child_dev_config {
 122  	u16 handle;
 123  	u16 device_type;
 124  	u8 not_common1[12];
 125  	u8 dvo_port;
 126  	u8 i2c_pin;
 127  	u8 slave_addr;
 128  	u8 ddc_pin;
 129  	u16 edid_ptr;
 130  	u8 not_common3[6];
 131  	u8 dvo_wiring;
 132  	u8 not_common4[4];
 133  } __attribute__ ((packed));
 134  
 135  struct bdb_general_definitions {
 136  	/* DDC GPIO */
 137  	u8 crt_ddc_gmbus_pin;
 138  
 139  	/* DPMS bits */
 140  	u8 dpms_acpi:1;
 141  	u8 skip_boot_crt_detect:1;
 142  	u8 dpms_aim:1;
 143  	u8 rsvd1:5;		/* finish byte */
 144  
 145  	/* boot device bits */
 146  	u8 boot_display[2];
 147  	u8 child_dev_size;
 148  
 149  	/*
 150  	 * Device info:
 151  	 * If TV is present, it'll be at devices[0].
 152  	 * LVDS will be next, either devices[0] or [1], if present.
 153  	 * On some platforms the number of device is 6. But could be as few as
 154  	 * 4 if both TV and LVDS are missing.
 155  	 * And the device num is related with the size of general definition
 156  	 * block. It is obtained by using the following formula:
 157  	 * number = (block_size - sizeof(bdb_general_definitions))/
 158  	 *           sizeof(child_device_config);
 159  	 */
 160  	struct common_child_dev_config devices[];
 161  } __attribute__ ((packed));
 162  
 163  struct bdb_driver_features {
 164  	u8 boot_dev_algorithm:1;
 165  	u8 block_display_switch:1;
 166  	u8 allow_display_switch:1;
 167  	u8 hotplug_dvo:1;
 168  	u8 dual_view_zoom:1;
 169  	u8 int15h_hook:1;
 170  	u8 sprite_in_clone:1;
 171  	u8 primary_lfp_id:1;
 172  
 173  	u16 boot_mode_x;
 174  	u16 boot_mode_y;
 175  	u8 boot_mode_bpp;
 176  	u8 boot_mode_refresh;
 177  
 178  	u16 enable_lfp_primary:1;
 179  	u16 selective_mode_pruning:1;
 180  	u16 dual_frequency:1;
 181  	u16 render_clock_freq:1;	/* 0: high freq; 1: low freq */
 182  	u16 nt_clone_support:1;
 183  	u16 power_scheme_ui:1;	/* 0: CUI; 1: 3rd party */
 184  	u16 sprite_display_assign:1;	/* 0: secondary; 1: primary */
 185  	u16 cui_aspect_scaling:1;
 186  	u16 preserve_aspect_ratio:1;
 187  	u16 sdvo_device_power_down:1;
 188  	u16 crt_hotplug:1;
 189  	u16 lvds_config:2;
 190  	u16 tv_hotplug:1;
 191  	u16 hdmi_config:2;
 192  
 193  	u8 static_display:1;
 194  	u8 reserved2:7;
 195  	u16 legacy_crt_max_x;
 196  	u16 legacy_crt_max_y;
 197  	u8 legacy_crt_max_refresh;
 198  
 199  	u8 hdmi_termination;
 200  	u8 custom_vbt_version;
 201  } __attribute__ ((packed));
 202  
 203  struct bdb_lvds_options {
 204  	u8 panel_type;
 205  	u8 rsvd1;
 206  	/* LVDS capabilities, stored in a dword */
 207  	u8 pfit_mode:2;
 208  	u8 pfit_text_mode_enhanced:1;
 209  	u8 pfit_gfx_mode_enhanced:1;
 210  	u8 pfit_ratio_auto:1;
 211  	u8 pixel_dither:1;
 212  	u8 lvds_edid:1;
 213  	u8 rsvd2:1;
 214  	u8 rsvd4;
 215  } __attribute__ ((packed));
 216  
 217  struct bdb_sdvo_lvds_options {
 218  	u8 panel_backlight;
 219  	u8 h40_set_panel_type;
 220  	u8 panel_type;
 221  	u8 ssc_clk_freq;
 222  	u16 als_low_trip;
 223  	u16 als_high_trip;
 224  	u8 sclalarcoeff_tab_row_num;
 225  	u8 sclalarcoeff_tab_row_size;
 226  	u8 coefficient[8];
 227  	u8 panel_misc_bits_1;
 228  	u8 panel_misc_bits_2;
 229  	u8 panel_misc_bits_3;
 230  	u8 panel_misc_bits_4;
 231  } __attribute__ ((packed));
 232  
 233  
 234  static const size_t ignore_checksum = 1;
 235  
 236  #define BDB_GENERAL_FEATURES	  1
 237  #define BDB_GENERAL_DEFINITIONS	  2
 238  
 239  #define BDB_DRIVER_FEATURES	 12
 240  #define BDB_SDVO_LVDS_OPTIONS	 22
 241  #define BDB_SDVO_PANEL_DTDS	 23
 242  #define BDB_LVDS_OPTIONS	 40
 243  #define BDB_LVDS_LFP_DATA_PTRS	 41
 244  #define BDB_LVDS_LFP_DATA	 42
 245  
 246  #define BDB_SKIP		254
 247  
 248  /* print helpers */
 249  static void print(const char *format, ...)
 250  {
 251  	va_list args;
 252  	fprintf(stdout, "VBTTOOL: ");
 253  	va_start(args, format);
 254  	vfprintf(stdout, format, args);
 255  	va_end(args);
 256  }
 257  
 258  static void printt(const char *format, ...)
 259  {
 260  	va_list args;
 261  	fprintf(stdout, "\t");
 262  	va_start(args, format);
 263  	vfprintf(stdout, format, args);
 264  	va_end(args);
 265  }
 266  
 267  static void printwarn(const char *format, ...)
 268  {
 269  	va_list args;
 270  	fprintf(stderr, "VBTTOOL: WARN: ");
 271  	va_start(args, format);
 272  	vfprintf(stderr, format, args);
 273  	va_end(args);
 274  }
 275  
 276  static void printerr(const char *format, ...)
 277  {
 278  	va_list args;
 279  	fprintf(stderr, "VBTTOOL: ERR: ");
 280  	va_start(args, format);
 281  	vfprintf(stderr, format, args);
 282  	va_end(args);
 283  }
 284  
 285  struct fileobject {
 286  	unsigned char *data;
 287  	size_t size;
 288  };
 289  
 290  /* file object helpers */
 291  
 292  /*
 293   * Alloc a file object of given size.
 294   * Returns NULL on error.
 295   */
 296  static struct fileobject *malloc_fo(const size_t size)
 297  {
 298  	struct fileobject *fo;
 299  	if (!size)
 300  		return NULL;
 301  
 302  	fo = malloc(sizeof(*fo));
 303  	if (!fo)
 304  		return NULL;
 305  	fo->data = malloc(size);
 306  	if (!fo->data) {
 307  		free(fo);
 308  		return NULL;
 309  	}
 310  	fo->size = size;
 311  
 312  	return fo;
 313  }
 314  
 315  /* Free a fileobject structure */
 316  static void free_fo(struct fileobject *fo)
 317  {
 318  	if (fo) {
 319  		free(fo->data);
 320  		free(fo);
 321  	}
 322  }
 323  
 324  /* Resize file object and keep memory content */
 325  static struct fileobject *remalloc_fo(struct fileobject *old,
 326  				      const size_t size)
 327  {
 328  	struct fileobject *fo = old;
 329  
 330  	if (!old || !size)
 331  		return NULL;
 332  
 333  	fo->data = realloc(fo->data, size);
 334  	if (!fo->data)
 335  		return NULL;
 336  
 337  	if (fo->size < size)
 338  		memset(&fo->data[fo->size], 0, size - fo->size);
 339  
 340  	fo->size = size;
 341  
 342  	return fo;
 343  }
 344  
 345  /*
 346   * Creates a new subregion copy of fileobject.
 347   * Returns NULL if offset is greater than fileobject size.
 348   * Returns NULL on error.
 349   */
 350  static struct fileobject *malloc_fo_sub(const struct fileobject *old,
 351  					const size_t off)
 352  {
 353  	struct fileobject *fo;
 354  
 355  	if (!old || off > old->size)
 356  		return NULL;
 357  
 358  	fo = malloc_fo(old->size - off);
 359  	if (!fo)
 360  		return NULL;
 361  
 362  	memcpy(fo->data, old->data + off, fo->size);
 363  
 364  	return fo;
 365  }
 366  
 367  /* file helpers */
 368  
 369  /* Create fileobject from file */
 370  static struct fileobject *read_file(const char *filename)
 371  {
 372  	FILE *fd = fopen(filename, "rb");
 373  	off_t read_size = DEF_ALLOC;
 374  
 375  	if (!fd) {
 376  		printerr("%s open failed: %s\n", filename, strerror(errno));
 377  		return NULL;
 378  	}
 379  
 380  	struct fileobject *fo = malloc_fo(read_size);
 381  	if (!fo) {
 382  		printerr("malloc failed\n");
 383  		fclose(fd);
 384  		return NULL;
 385  	}
 386  
 387  	off_t total_bytes_read = 0, bytes_read;
 388  	while ((bytes_read = fread(fo->data + total_bytes_read, 1, read_size, fd)) > 0) {
 389  		total_bytes_read += bytes_read;
 390  		struct fileobject *newfo = remalloc_fo(fo, fo->size + read_size);
 391  		if (!newfo) {
 392  			fclose(fd);
 393  			free_fo(fo);
 394  			return NULL;
 395  		}
 396  		fo = newfo;
 397  	}
 398  
 399  	if (!total_bytes_read) {
 400  		fclose(fd);
 401  		free_fo(fo);
 402  		return NULL;
 403  	}
 404  
 405  	if (fclose(fd)) {
 406  		printerr("%s close failed: %s\n", filename, strerror(errno));
 407  		free_fo(fo);
 408  		return NULL;
 409  	}
 410  
 411  	fo->size = total_bytes_read;
 412  
 413  	return fo;
 414  }
 415  
 416  /* Create fileobject from physical memory at given address of size 64 KiB */
 417  static struct fileobject *read_physmem(size_t addr)
 418  {
 419  	const int fd = open("/dev/mem", O_RDONLY);
 420  	const size_t size = 64 * 2 * KiB;
 421  	if (fd < 0) {
 422  		printerr("/dev/mem open failed: %s\n", strerror(errno));
 423  		return NULL;
 424  	}
 425  
 426  	const void *data = mmap(0, size, PROT_READ, MAP_SHARED, fd, addr);
 427  	if (data == MAP_FAILED) {
 428  		close(fd);
 429  		printerr("mmap failed: %s\n", strerror(errno));
 430  		return NULL;
 431  	}
 432  
 433  	struct fileobject *fo = malloc_fo(size);
 434  	if (!fo) {
 435  		printerr("malloc failed\n");
 436  		munmap((void *)data, size);
 437  		close(fd);
 438  		return NULL;
 439  	}
 440  
 441  	memcpy(fo->data, data, size);
 442  	munmap((void *)data, size);
 443  
 444  	if (close(fd)) {
 445  		printerr("/dev/mem close failed: %s\n", strerror(errno));
 446  		free_fo(fo);
 447  		return NULL;
 448  	}
 449  
 450  	return fo;
 451  }
 452  
 453  /* Write fileobject contents to file */
 454  static int write_file(const char *filename, const struct fileobject *fo)
 455  {
 456  	FILE *fd_out = fopen(filename, "wb");
 457  
 458  	if (!fd_out) {
 459  		printerr("%s open failed: %s\n", filename, strerror(errno));
 460  		return 1;
 461  	}
 462  	if (fwrite(fo->data, 1, fo->size, fd_out) != fo->size) {
 463  		fclose(fd_out);
 464  		return 1;
 465  	}
 466  	return fclose(fd_out);
 467  }
 468  
 469  /* dump VBT contents in human readable form */
 470  static void dump_vbt(const struct fileobject *fo)
 471  {
 472  	if (fo->size < sizeof(struct vbt_header))
 473  		return;
 474  
 475  	const struct vbt_header *head = (const struct vbt_header *)fo->data;
 476  	const struct bdb_header *bdb;
 477  	const u8 *ptr;
 478  	int i;
 479  	int is_first_skip = 1;
 480  
 481  	printt("signature: <%20.20s>\n", head->signature);
 482  	printt("version: %d.%02d\n", head->version / 100,
 483  	       head->version % 100);
 484  	if (head->header_size != sizeof(struct vbt_header))
 485  		printt("header size: 0x%x\n", head->header_size);
 486  	printt("VBT size: 0x%x\n", head->vbt_size);
 487  	printt("VBT checksum: 0x%x\n", head->vbt_checksum);
 488  	if (head->reserved0)
 489  		printt("header reserved0: 0x%x\n", head->reserved0);
 490  	if (head->bdb_offset != sizeof(struct vbt_header))
 491  		printt("BDB offset: 0x%x\n", head->bdb_offset);
 492  
 493  	for (i = 0; i < 4; i++)
 494  		if (head->aim_offset[i])
 495  			printt("AIM[%d] offset: 0x%x\n", i,
 496  			       head->aim_offset[i]);
 497  	if (head->bdb_offset + sizeof(*bdb) > fo->size)
 498  		return;
 499  	bdb = (const void *) (fo->data + head->bdb_offset);
 500  
 501  	if (memcmp("BIOS_DATA_BLOCK ", bdb->signature, 16) != 0) {
 502  		printerr("invalid BDB signature:%s\n",
 503  			bdb->signature);
 504  		exit(1);
 505  	}
 506  	printt("BDB version: %d.%02d\n", bdb->version / 100,
 507  	       bdb->version % 100);
 508  	if (bdb->header_size != sizeof(struct bdb_header))
 509  		printt("BDB header size: 0x%x\n", bdb->header_size);
 510  	if (bdb->bdb_size != head->vbt_size - head->bdb_offset)
 511  		printt("BDB size: 0x%x\n", bdb->bdb_size);
 512  	for (ptr = (const u8 *) bdb + bdb->header_size;
 513  	     ptr < (const u8 *) bdb + bdb->bdb_size;) {
 514  		u16 secsz = (ptr[1] | (ptr[2] << 8));
 515  		u8 sectype = ptr[0];
 516  		const u8 *section = ptr + 3;
 517  
 518  		printt("section type %d, size 0x%x\n", sectype, secsz);
 519  		ptr += secsz + 3;
 520  		switch (sectype) {
 521  		case BDB_GENERAL_FEATURES:{
 522  				const struct bdb_general_features *sec =
 523  				    (const void *) section;
 524  				printt("General features:\n");
 525  
 526  				if (sec->panel_fitting)
 527  					printt("\tpanel_fitting = 0x%x\n",
 528  					       sec->panel_fitting);
 529  				if (sec->flexaim)
 530  					printt("\tflexaim = 0x%x\n",
 531  					       sec->flexaim);
 532  				if (sec->msg_enable)
 533  					printt("\tmsg_enable = 0x%x\n",
 534  					       sec->msg_enable);
 535  				if (sec->clear_screen)
 536  					printt("\tclear_screen = 0x%x\n",
 537  					       sec->clear_screen);
 538  				if (sec->color_flip)
 539  					printt("\tcolor_flip = 0x%x\n",
 540  					       sec->color_flip);
 541  				if (sec->download_ext_vbt)
 542  					printt
 543  					    ("\tdownload_ext_vbt = 0x%x\n",
 544  					     sec->download_ext_vbt);
 545  				printt("\t*enable_ssc = 0x%x\n",
 546  				       sec->enable_ssc);
 547  				printt("\t*ssc_freq = 0x%x\n",
 548  				       sec->ssc_freq);
 549  				if (sec->enable_lfp_on_override)
 550  					printt
 551  					    ("\tenable_lfp_on_override = 0x%x\n",
 552  					     sec->enable_lfp_on_override);
 553  				if (sec->disable_ssc_ddt)
 554  					printt
 555  					    ("\tdisable_ssc_ddt = 0x%x\n",
 556  					     sec->disable_ssc_ddt);
 557  				if (sec->rsvd7)
 558  					printt("\trsvd7 = 0x%x\n",
 559  					       sec->rsvd7);
 560  				printt("\t*display_clock_mode = 0x%x\n",
 561  				       sec->display_clock_mode);
 562  				if (sec->rsvd8)
 563  					printt("\trsvd8 = 0x%x\n",
 564  					       sec->rsvd8);
 565  				printt("\tdisable_smooth_vision = 0x%x\n",
 566  				       sec->disable_smooth_vision);
 567  				if (sec->single_dvi)
 568  					printt("\tsingle_dvi = 0x%x\n",
 569  					       sec->single_dvi);
 570  				if (sec->rsvd9)
 571  					printt("\trsvd9 = 0x%x\n",
 572  					       sec->rsvd9);
 573  				printt
 574  				    ("\t*fdi_rx_polarity_inverted = 0x%x\n",
 575  				     sec->fdi_rx_polarity_inverted);
 576  				if (sec->rsvd10)
 577  					printt("\trsvd10 = 0x%x\n",
 578  					       sec->rsvd10);
 579  				if (sec->legacy_monitor_detect)
 580  					printt
 581  					    ("\tlegacy_monitor_detect = 0x%x\n",
 582  					     sec->legacy_monitor_detect);
 583  				printt("\t*int_crt_support = 0x%x\n",
 584  				       sec->int_crt_support);
 585  				printt("\t*int_tv_support = 0x%x\n",
 586  				       sec->int_tv_support);
 587  				if (sec->int_efp_support)
 588  					printt
 589  					    ("\tint_efp_support = 0x%x\n",
 590  					     sec->int_efp_support);
 591  				if (sec->dp_ssc_enb)
 592  					printt("\tdp_ssc_enb = 0x%x\n",
 593  					       sec->dp_ssc_enb);
 594  				if (sec->dp_ssc_freq)
 595  					printt("\tdp_ssc_freq = 0x%x\n",
 596  					       sec->dp_ssc_freq);
 597  				if (sec->rsvd11)
 598  					printt("\trsvd11 = 0x%x\n",
 599  					       sec->rsvd11);
 600  				break;
 601  			}
 602  		case BDB_DRIVER_FEATURES:{
 603  				const struct bdb_driver_features *sec =
 604  				    (const void *) section;
 605  				printt("\t*LVDS config: %d\n",
 606  				       sec->lvds_config);
 607  				printt("\t*Dual frequency: %d\n",
 608  				       sec->dual_frequency);
 609  
 610  				break;
 611  			}
 612  		case BDB_SDVO_LVDS_OPTIONS:{
 613  				const struct bdb_sdvo_lvds_options *sec =
 614  				    (const void *) section;
 615  				printt("\t*Panel type: %d\n",
 616  				       sec->panel_type);
 617  
 618  				break;
 619  			}
 620  		case BDB_GENERAL_DEFINITIONS:{
 621  				const struct bdb_general_definitions *sec =
 622  				    (const void *) section;
 623  				int ndev;
 624  				printt("\t*CRT DDC GMBUS pin: %d\n",
 625  				       sec->crt_ddc_gmbus_pin);
 626  
 627  				printt("\tDPMS ACPI: %d\n",
 628  				       sec->dpms_acpi);
 629  				printt("\tSkip boot CRT detect: %d\n",
 630  				       sec->skip_boot_crt_detect);
 631  				printt("\tDPMS aim: %d\n", sec->dpms_aim);
 632  				if (sec->rsvd1)
 633  					printt("\trsvd1: 0x%x\n",
 634  					       sec->rsvd1);
 635  				printt("\tboot_display: { %x, %x }\n",
 636  				       sec->boot_display[0],
 637  				       sec->boot_display[1]);
 638  				if (sec->child_dev_size !=
 639  				    sizeof(struct common_child_dev_config))
 640  					printt("\tchild_dev_size: %d\n",
 641  					       sec->child_dev_size);
 642  				ndev = (secsz - sizeof(*sec)) /
 643  					sizeof(struct common_child_dev_config);
 644  				printt("\t%d devices\n", ndev);
 645  				for (i = 0; i < ndev; i++) {
 646  					printt("\t*device type: %x ",
 647  					       sec->devices[i].
 648  					       device_type);
 649  #define	 DEVICE_TYPE_INT_LFP	0x1022
 650  #define	 DEVICE_TYPE_INT_TV	0x1009
 651  #define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR	0x6052
 652  					switch (sec->devices[i].device_type) {
 653  					case DEVICE_TYPE_INT_LFP:
 654  						printt("(flat panel)\n");
 655  						break;
 656  					case DEVICE_TYPE_INT_TV:
 657  						printt("(TV)\n");
 658  						break;
 659  					case DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR:
 660  						printt
 661  						    ("(DVI)\n");
 662  						break;
 663  					case 0:
 664  						printt("(Empty)\n");
 665  						break;
 666  					default:
 667  						printt("(Unknown)\n");
 668  						break;
 669  					}
 670  					if (!sec->devices[i].device_type)
 671  						continue;
 672  					printt("\t *dvo_port: %x\n",
 673  					       sec->devices[i].dvo_port);
 674  					printt("\t *i2c_pin: %x\n",
 675  					       sec->devices[i].i2c_pin);
 676  					printt("\t *slave_addr: %x\n",
 677  					       sec->devices[i].slave_addr);
 678  					printt("\t *ddc_pin: %x\n",
 679  					       sec->devices[i].ddc_pin);
 680  					printt("\t *dvo_wiring: %x\n",
 681  					       sec->devices[i].dvo_wiring);
 682  					printt("\t edid_ptr: %x\n",
 683  					       sec->devices[i].edid_ptr);
 684  				}
 685  
 686  				break;
 687  			}
 688  		case BDB_SKIP:{
 689  				const struct vbios_data *sec =
 690  				    (const void *) section;
 691  				if (!is_first_skip)
 692  					break;
 693  				is_first_skip = 0;
 694  				printt("\ttype: %x\n", sec->type);
 695  				printt("\trelstage: %x\n", sec->relstage);
 696  				printt("\tchipset: %x\n", sec->chipset);
 697  				printt(sec->lvds_present ? "\tLVDS\n"
 698  				       : "\tNo LVDS\n");
 699  				printt(sec->tv_present ? "\tTV\n"
 700  				       : "\tNo TV\n");
 701  				if (sec->rsvd2)
 702  					printt("\trsvd2: 0x%x\n",
 703  					       sec->rsvd2);
 704  				for (i = 0; i < 4; i++)
 705  					if (sec->rsvd3[i])
 706  						printt
 707  						    ("\trsvd3[%d]: 0x%x\n",
 708  						     i, sec->rsvd3[i]);
 709  				printt("\tSignon: %.155s\n", sec->signon);
 710  				printt("\tCopyright: %.155s\n",
 711  				       sec->copyright);
 712  				printt("\tCode segment: %x\n",
 713  				       sec->code_segment);
 714  				printt("\tDOS Boot mode: %x\n",
 715  				       sec->dos_boot_mode);
 716  				printt("\tBandwidth percent: %x\n",
 717  				       sec->bandwidth_percent);
 718  				if (sec->rsvd4)
 719  					printt("\trsvd4: 0x%x\n",
 720  					       sec->rsvd4);
 721  				printt("\tBandwidth percent: %x\n",
 722  				       sec->resize_pci_bios);
 723  				if (sec->rsvd5)
 724  					printt("\trsvd5: 0x%x\n",
 725  					       sec->rsvd5);
 726  				break;
 727  			}
 728  		}
 729  	}
 730  }
 731  
 732  /* Returns a new fileobject containing a valid VBT */
 733  static void parse_vbt(const struct fileobject *fo,
 734  		      struct fileobject **vbt)
 735  {
 736  	*vbt = NULL;
 737  
 738  	if (fo->size < sizeof(struct vbt_header)) {
 739  		printerr("image is too small\n");
 740  		return;
 741  	}
 742  
 743  	const struct vbt_header *head =
 744  	    (const struct vbt_header *)fo->data;
 745  
 746  	if (memcmp(head->signature, "$VBT", 4) != 0) {
 747  		printerr("invalid VBT signature\n");
 748  		return;
 749  	}
 750  
 751  	if (!head->vbt_size || head->vbt_size > fo->size) {
 752  		printerr("invalid VBT size\n");
 753  		return;
 754  	}
 755  
 756  	if (!head->bdb_offset ||
 757  	    head->bdb_offset > fo->size - sizeof(struct bdb_header)) {
 758  		printerr("invalid BDB offset\n");
 759  		return;
 760  	}
 761  
 762  	if (!head->header_size || head->header_size > fo->size) {
 763  		printerr("invalid header size\n");
 764  		return;
 765  	}
 766  
 767  	const struct bdb_header *const bdb_head =
 768  	    (const struct bdb_header *)((const u8 *)head + head->bdb_offset);
 769  	if (memcmp(bdb_head->signature, "BIOS_DATA_BLOCK ", 16) != 0) {
 770  		printerr("invalid BDB signature\n");
 771  		return;
 772  	}
 773  
 774  	if (!bdb_head->header_size || bdb_head->header_size > fo->size) {
 775  		printerr("invalid BDB header size\n");
 776  		return;
 777  	}
 778  
 779  	/* Duplicate fo as caller is owner and remalloc frees the object */
 780  	struct fileobject *dupfo = malloc_fo_sub(fo, 0);
 781  	if (!dupfo) {
 782  		printerr("malloc failed\n");
 783  		return;
 784  	}
 785  
 786  	struct fileobject *newfo = remalloc_fo(dupfo, head->vbt_size);
 787  	if (!newfo) {
 788  		printerr("remalloc failed\n");
 789  		free_fo(dupfo);
 790  		return;
 791  	}
 792  
 793  	*vbt = newfo;
 794  }
 795  
 796  /* Option ROM checksum */
 797  static u8 checksum_vbios(const optionrom_header_t *oh)
 798  {
 799  	const u8 *ptr = (const u8 *)oh;
 800  	size_t i;
 801  
 802  	u8 cksum = 0;
 803  	for (i = 0; i < ((MIN(oh->size, 128)) * 512); i++)
 804  		cksum += ptr[i];
 805  
 806  	return cksum;
 807  }
 808  
 809  /* Verify Option ROM contents */
 810  static int is_valid_vbios(const struct fileobject *fo)
 811  {
 812  	if (fo->size > 64 * 2 * KiB) {
 813  		printerr("VBIOS is too big\n");
 814  		return 0;
 815  	}
 816  
 817  	if (fo->size < sizeof(optionrom_header_t)) {
 818  		printerr("VBIOS is too small\n");
 819  		return 0;
 820  	}
 821  
 822  	const optionrom_header_t *oh = (const optionrom_header_t *)fo->data;
 823  
 824  	if (oh->signature != 0xaa55) {
 825  		printerr("bad oprom signature: 0x%x\n", oh->signature);
 826  		return 0;
 827  	}
 828  
 829  	if (oh->size == 0 || oh->size > 0x80 || oh->size * 512 > fo->size) {
 830  		printerr("bad oprom size: 0x%x\n", oh->size);
 831  		return 0;
 832  	}
 833  
 834  	const u8 cksum = checksum_vbios(oh);
 835  	if (cksum) {
 836  		if (!ignore_checksum) {
 837  			printerr("bad oprom checksum: 0x%x\n", cksum);
 838  			return 0;
 839  		}
 840  		printwarn("bad oprom checksum: 0x%x\n", cksum);
 841  	}
 842  
 843  	if (oh->pcir_offset + sizeof(optionrom_pcir_t) > fo->size) {
 844  		printerr("bad pcir offset: 0x%x\n", oh->pcir_offset);
 845  		return 0;
 846  	}
 847  
 848  	if (oh->pcir_offset) {
 849  		const optionrom_pcir_t *pcir;
 850  		pcir = (const optionrom_pcir_t *)
 851  		    ((const u8 *)oh + oh->pcir_offset);
 852  
 853  		if (pcir->signature != 0x52494350) {
 854  			printerr("Invalid PCIR signature\n");
 855  			return 0;
 856  		}
 857  
 858  		if (pcir->vendor != 0x8086) {
 859  			printerr("Not an Intel VBIOS\n");
 860  			return 0;
 861  		}
 862  
 863  		if (pcir->classcode[0] != 0 || pcir->classcode[1] != 0 ||
 864  		    pcir->classcode[2] != 3) {
 865  			printerr("Not a VGA Option Rom\n");
 866  			return 0;
 867  		}
 868  	} else {
 869  		printwarn("no PCIR header found\n");
 870  	}
 871  
 872  	return 1;
 873  }
 874  
 875  /*
 876   * Parse Option ROM and return a valid VBT fileobject.
 877   * Caller has to make sure that it is a valid VBIOS.
 878   * Return a NULL fileobject on error.
 879   */
 880  static void parse_vbios(const struct fileobject *fo,
 881  			struct fileobject **vbt)
 882  {
 883  	const optionrom_header_t *oh = (const optionrom_header_t *)fo->data;
 884  	size_t i;
 885  
 886  	*vbt = NULL;
 887  
 888  	if (!oh->vbt_offset) {
 889  		printerr("no VBT found\n");
 890  		return;
 891  	}
 892  
 893  	if (oh->vbt_offset > (fo->size - sizeof(struct vbt_header))) {
 894  		printerr("invalid VBT offset\n");
 895  		return;
 896  	}
 897  
 898  	struct fileobject *fo_vbt = malloc_fo_sub(fo, oh->vbt_offset);
 899  	if (fo_vbt) {
 900  		parse_vbt(fo_vbt, vbt);
 901  		free_fo(fo_vbt);
 902  		if (*vbt)
 903  			return;
 904  	}
 905  	printwarn("VBT wasn't found at specified offset of %04x\n",
 906  		  oh->vbt_offset);
 907  
 908  	for (i = sizeof(optionrom_header_t);
 909  	     i <= fo->size - sizeof(struct vbt_header); i++) {
 910  		struct fileobject *fo_vbt = malloc_fo_sub(fo, i);
 911  		if (!fo_vbt)
 912  			break;
 913  
 914  		parse_vbt(fo_vbt, vbt);
 915  
 916  		free_fo(fo_vbt);
 917  
 918  		if (*vbt)
 919  			return;
 920  	}
 921  }
 922  
 923  /* Short VBT summary in human readable form */
 924  static void print_vbt(const struct fileobject *fo)
 925  {
 926  	const struct bdb_header *bdb;
 927  
 928  	if (fo->size < sizeof(struct vbt_header))
 929  		return;
 930  
 931  	const struct vbt_header *head = (const struct vbt_header *)fo->data;
 932  
 933  	print("Found VBT:\n");
 934  	printt("signature: <%20.20s>\n", head->signature);
 935  	printt("version: %d.%02d\n", head->version / 100, head->version % 100);
 936  	if (head->header_size != sizeof(struct vbt_header))
 937  		printt("header size: 0x%x\n", head->header_size);
 938  	printt("VBT size: 0x%x\n", head->vbt_size);
 939  	printt("VBT checksum: 0x%x\n", head->vbt_checksum);
 940  
 941  	if (head->bdb_offset > (fo->size - sizeof(struct bdb_header))) {
 942  		printerr("invalid BDB offset\n");
 943  		return;
 944  	}
 945  	bdb = (const struct bdb_header *)
 946  	    ((const char *)head + head->bdb_offset);
 947  
 948  	if (memcmp("BIOS_DATA_BLOCK ", bdb->signature, 16) != 0) {
 949  		printerr("invalid BDB signature:%s\n", bdb->signature);
 950  		return;
 951  	}
 952  	printt("BDB version: %u.%02u\n", bdb->version / 100,
 953  	       bdb->version % 100);
 954  }
 955  
 956  static void print_usage(const char *argv0, struct option *long_options)
 957  {
 958  	size_t i = 0;
 959  	printf("\nUsage:\n");
 960  	printf("%s --<SOURCECMD> [filename] --<DESTCMD> [filename]\n\n", argv0);
 961  	printf("SOURCECMD set the VBT source. Supported:\n");
 962  	printf(" %-10s: Legacy BIOS area at phys. memory 0xc0000\n",
 963  	       "inlegacy");
 964  	printf(" %-10s: Read raw Intel VBT file\n", "invbt");
 965  	printf(" %-10s: Read VBT from Intel Option ROM file\n\n", "inoprom");
 966  	printf("DESTCMD set the VBT destination. Supported:\n");
 967  	printf(" %-10s: Print VBT in human readable form\n", "outdump");
 968  	printf(" %-10s: Write raw Intel VBT file\n", "outvbt");
 969  	printf(" %-10s: Patch existing Intel Option ROM\n\n", "patchoprom");
 970  
 971  	printf("Supported arguments:\n");
 972  	while (long_options[i].name) {
 973  		printf("\t-%c --%s %s\n", long_options[i].val,
 974  		       long_options[i].name, long_options[i].has_arg ?
 975  		       "<path>"  : "");
 976  		i++;
 977  	};
 978  }
 979  
 980  /* Fix VBIOS header and PCIR */
 981  static int fix_vbios_header(struct fileobject *fo)
 982  {
 983  	if (!fo || fo->size < sizeof(optionrom_header_t))
 984  		return 1;
 985  
 986  	optionrom_header_t *oh = (optionrom_header_t *)fo->data;
 987  
 988  	/* Fix size alignment */
 989  	if (fo->size % 512) {
 990  		print("Aligning size to 512\n");
 991  		fo = remalloc_fo(fo, (fo->size + 511) / 512 * 512);
 992  		if (!fo)
 993  			return 1;
 994  		oh = (optionrom_header_t *)fo->data;
 995  	}
 996  
 997  	/* Fix size field */
 998  	oh->size = fo->size / 512;
 999  
1000  	/* Fix checksum field */
1001  	oh->checksum = -(checksum_vbios(oh) - oh->checksum);
1002  
1003  	return 0;
1004  }
1005  
1006  /* Return the VBT structure size in bytes */
1007  static size_t vbt_size(const struct fileobject *fo)
1008  {
1009  	if (!fo || fo->size < sizeof(struct vbt_header))
1010  		return 0;
1011  	const struct vbt_header *head = (const struct vbt_header *)fo->data;
1012  
1013  	return head->vbt_size;
1014  }
1015  
1016  /*
1017   * Patch an Intel Option ROM with new VBT.
1018   * Caller has to make sure that VBIOS and VBT are valid.
1019   * Return 1 on error.
1020   */
1021  static int patch_vbios(struct fileobject *fo,
1022  		       const struct fileobject *fo_vbt)
1023  {
1024  	optionrom_header_t *oh = (optionrom_header_t *)fo->data;
1025  	struct vbt_header *head;
1026  
1027  	struct fileobject *old_vbt = NULL;
1028  	parse_vbios(fo, &old_vbt);
1029  
1030  	if (old_vbt) {
1031  		if (oh->vbt_offset + vbt_size(old_vbt) == fo->size) {
1032  			/* Located at the end of file - reduce file size */
1033  			if (fo->size < vbt_size(old_vbt)) {
1034  				free_fo(old_vbt);
1035  				return 1;
1036  			}
1037  			fo = remalloc_fo(fo, fo->size - vbt_size(old_vbt));
1038  			if (!fo) {
1039  				printerr("Failed to allocate memory\n");
1040  				free_fo(old_vbt);
1041  				return 1;
1042  			}
1043  			oh = (optionrom_header_t *)fo->data;
1044  			oh->vbt_offset = 0;
1045  		} else if (vbt_size(old_vbt) < vbt_size(fo_vbt)) {
1046  			/* In the middle of the file - Remove old VBT */
1047  			memset(fo->data + oh->vbt_offset, 0xff,
1048  			       vbt_size(old_vbt));
1049  			oh->vbt_offset = 0;
1050  		} else {
1051  			/* New VBT overwrites existing one - Clear memory */
1052  			memset(fo->data + oh->vbt_offset, 0xff,
1053  			       vbt_size(old_vbt));
1054  		}
1055  
1056  		free_fo(old_vbt);
1057  	}
1058  
1059  	if (!oh->vbt_offset) {
1060  		print("increasing VBIOS to append VBT\n");
1061  		if ((fo->size + vbt_size(fo_vbt)) >= 2 * 64 * KiB) {
1062  			printerr("VBT won't fit\n");
1063  			return 1;
1064  		}
1065  
1066  		oh->vbt_offset = fo->size;
1067  		fo = remalloc_fo(fo, fo->size + vbt_size(fo_vbt));
1068  		if (!fo) {
1069  			printerr("Failed to allocate memory\n");
1070  			return 1;
1071  		}
1072  		oh = (optionrom_header_t *)fo->data;
1073  	}
1074  
1075  	head = (struct vbt_header *)((u8 *)oh + oh->vbt_offset);
1076  	memcpy(head, fo_vbt->data, vbt_size(fo_vbt));
1077  
1078  	return 0;
1079  }
1080  
1081  int main(int argc, char **argv)
1082  {
1083  	int opt, ret, option_index = 0;
1084  
1085  	size_t has_input = 0, has_output = 0;
1086  	size_t dump = 0, in_legacy = 0;
1087  	char *in_vbt = NULL, *in_oprom = NULL;
1088  	char *out_vbt = NULL, *patch_oprom = NULL;
1089  	static struct option long_options[] = {
1090  		{"help", 0, 0, 'h'},
1091  		{"outdump", 0, 0, 'd'},
1092  		{"inlegacy", 0, 0, 'l'},
1093  		{"invbt", required_argument, 0, 'f'},
1094  		{"inoprom", required_argument, 0, 'o'},
1095  		{"outvbt", required_argument, 0, 'v'},
1096  		{"patchoprom", required_argument, 0, 'p'},
1097  		{0, 0, 0, 0}
1098  	};
1099  
1100  	while ((opt = getopt_long(argc, argv, "hdlf:o:v:p:i",
1101  		   long_options, &option_index)) != EOF) {
1102  		switch (opt) {
1103  		case 'd':
1104  			dump = 1;
1105  			has_output = 1;
1106  			break;
1107  		case 'l':
1108  			in_legacy = 1;
1109  			has_input = 1;
1110  			break;
1111  		case 'f':
1112  			in_vbt = strdup(optarg);
1113  			has_input = 1;
1114  			break;
1115  		case 'o':
1116  			in_oprom = strdup(optarg);
1117  			has_input = 1;
1118  			break;
1119  		case 'v':
1120  			out_vbt = strdup(optarg);
1121  			has_output = 1;
1122  			break;
1123  		case 'p':
1124  			patch_oprom = strdup(optarg);
1125  			has_output = 1;
1126  			break;
1127  		case '?':
1128  		case 'h':
1129  			print_usage(argv[0], long_options);
1130  			exit(0);
1131  			break;
1132  		}
1133  	}
1134  
1135  	if (!has_input)
1136  		printerr("No input specified !\n");
1137  	if (!has_output)
1138  		printerr("No output specified !\n");
1139  	if (argc < 2 || argc > 6 || !has_input || !has_output) {
1140  		print_usage(argv[0], long_options);
1141  		return 1;
1142  	}
1143  
1144  	struct fileobject *fo;
1145  
1146  	if (in_legacy)
1147  		fo = read_physmem(0xc0000);
1148  	else if (in_vbt)
1149  		fo = read_file(in_vbt);
1150  	else
1151  		fo = read_file(in_oprom);
1152  
1153  	if (!fo) {
1154  		printerr("Failed to read input file\n");
1155  		return 1;
1156  	}
1157  
1158  	struct fileobject *vbt = NULL;
1159  	if (in_legacy || in_oprom) {
1160  		if (!is_valid_vbios(fo)) {
1161  			printerr("Invalid input file\n");
1162  
1163  			free_fo(fo);
1164  			return 1;
1165  		}
1166  		parse_vbios(fo, &vbt);
1167  	} else
1168  		parse_vbt(fo, &vbt);
1169  
1170  	free_fo(fo);
1171  
1172  	if (!vbt) {
1173  		printerr("Failed to find VBT.\n");
1174  		return 1;
1175  	}
1176  
1177  	if (!dump)
1178  		print_vbt(vbt);
1179  
1180  	ret = 0;
1181  	if (dump) {
1182  		dump_vbt(vbt);
1183  	} else if (out_vbt) {
1184  		if (write_file(out_vbt, vbt)) {
1185  			printerr("Failed to write VBT\n");
1186  			ret = 1;
1187  		} else {
1188  			print("VBT written to %s\n", out_vbt);
1189  		}
1190  	} else if (patch_oprom) {
1191  		fo = read_file(patch_oprom);
1192  		if (!fo) {
1193  			printerr("Failed to read input file\n");
1194  			ret = 1;
1195  		}
1196  		if (ret != 1 && !is_valid_vbios(fo)) {
1197  			printerr("Invalid input file\n");
1198  			ret = 1;
1199  		}
1200  		if (ret != 1 && patch_vbios(fo, vbt)) {
1201  			printerr("Failed to patch VBIOS\n");
1202  			ret = 1;
1203  		}
1204  		if (ret != 1 && fix_vbios_header(fo)) {
1205  			printerr("Failed to fix VBIOS header\n");
1206  			ret = 1;
1207  		}
1208  		if (ret != 1 && write_file(patch_oprom, fo)) {
1209  			printerr("Failed to write VBIOS\n");
1210  			ret = 1;
1211  		}
1212  		free_fo(fo);
1213  		if (ret != 1)
1214  			print("VBIOS %s successfully patched\n", patch_oprom);
1215  	}
1216  
1217  	/* cleanup */
1218  	if (patch_oprom)
1219  		free(patch_oprom);
1220  	if (out_vbt)
1221  		free(out_vbt);
1222  	if (in_vbt)
1223  		free(in_vbt);
1224  	if (in_oprom)
1225  		free(in_oprom);
1226  
1227  	free_fo(vbt);
1228  
1229  	return ret;
1230  }