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 }