lint-000-license-headers: Add src/sbom/TAGS to exception list
[coreboot.git] / util / intelvbttool / intelvbttool.c
blobc8d7a088d3a75b6b981b31ae7af99cfabfdf9452
1 /* SPDX-License-Identifier: GPL-2.0-only */
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>
17 typedef uint8_t u8;
18 typedef uint16_t u16;
19 typedef uint32_t u32;
21 #define DEF_ALLOC 1024
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;
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;
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));
59 struct bdb_header {
60 u8 signature[16];
61 u16 version;
62 u16 header_size;
63 u16 bdb_size;
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));
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;
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 */
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 */
109 /* bits 4 */
110 u8 legacy_monitor_detect;
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));
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));
135 struct bdb_general_definitions {
136 /* DDC GPIO */
137 u8 crt_ddc_gmbus_pin;
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 */
145 /* boot device bits */
146 u8 boot_display[2];
147 u8 child_dev_size;
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);
160 struct common_child_dev_config devices[0];
161 } __attribute__ ((packed));
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;
173 u16 boot_mode_x;
174 u16 boot_mode_y;
175 u8 boot_mode_bpp;
176 u8 boot_mode_refresh;
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;
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;
199 u8 hdmi_termination;
200 u8 custom_vbt_version;
201 } __attribute__ ((packed));
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));
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));
234 static const size_t ignore_checksum = 1;
236 #define BDB_GENERAL_FEATURES 1
237 #define BDB_GENERAL_DEFINITIONS 2
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
246 #define BDB_SKIP 254
248 /* print helpers */
249 static void print(const char *format, ...)
251 va_list args;
252 fprintf(stdout, "VBTTOOL: ");
253 va_start(args, format);
254 vfprintf(stdout, format, args);
255 va_end(args);
258 static void printt(const char *format, ...)
260 va_list args;
261 fprintf(stdout, "\t");
262 va_start(args, format);
263 vfprintf(stdout, format, args);
264 va_end(args);
267 static void printwarn(const char *format, ...)
269 va_list args;
270 fprintf(stderr, "VBTTOOL: WARN: ");
271 va_start(args, format);
272 vfprintf(stderr, format, args);
273 va_end(args);
276 static void printerr(const char *format, ...)
278 va_list args;
279 fprintf(stderr, "VBTTOOL: ERR: ");
280 va_start(args, format);
281 vfprintf(stderr, format, args);
282 va_end(args);
285 struct fileobject {
286 unsigned char *data;
287 size_t size;
290 /* file object helpers */
293 * Alloc a file object of given size.
294 * Returns NULL on error.
296 static struct fileobject *malloc_fo(const size_t size)
298 struct fileobject *fo;
299 if (!size)
300 return NULL;
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;
310 fo->size = size;
312 return fo;
315 /* Free a fileobject structure */
316 static void free_fo(struct fileobject *fo)
318 if (fo) {
319 free(fo->data);
320 free(fo);
324 /* Resize file object and keep memory content */
325 static struct fileobject *remalloc_fo(struct fileobject *old,
326 const size_t size)
328 struct fileobject *fo = old;
330 if (!old || !size)
331 return NULL;
333 fo->data = realloc(fo->data, size);
334 if (!fo->data)
335 return NULL;
337 if (fo->size < size)
338 memset(&fo->data[fo->size], 0, size - fo->size);
340 fo->size = size;
342 return fo;
346 * Creates a new subregion copy of fileobject.
347 * Returns NULL if offset is greater than fileobject size.
348 * Returns NULL on error.
350 static struct fileobject *malloc_fo_sub(const struct fileobject *old,
351 const size_t off)
353 struct fileobject *fo;
355 if (!old || off > old->size)
356 return NULL;
358 fo = malloc_fo(old->size - off);
359 if (!fo)
360 return NULL;
362 memcpy(fo->data, old->data + off, fo->size);
364 return fo;
367 /* file helpers */
369 /* Create fileobject from file */
370 static struct fileobject *read_file(const char *filename)
372 FILE *fd = fopen(filename, "rb");
373 off_t read_size = DEF_ALLOC;
375 if (!fd) {
376 printerr("%s open failed: %s\n", filename, strerror(errno));
377 return NULL;
380 struct fileobject *fo = malloc_fo(read_size);
381 if (!fo) {
382 printerr("malloc failed\n");
383 fclose(fd);
384 return NULL;
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;
396 fo = newfo;
399 if (!total_bytes_read) {
400 fclose(fd);
401 free_fo(fo);
402 return NULL;
405 if (fclose(fd)) {
406 printerr("%s close failed: %s\n", filename, strerror(errno));
407 free_fo(fo);
408 return NULL;
411 fo->size = total_bytes_read;
413 return fo;
416 /* Create fileobject from physical memory at given address of size 64 KiB */
417 static struct fileobject *read_physmem(size_t addr)
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;
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;
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;
441 memcpy(fo->data, data, size);
442 munmap((void *)data, size);
444 if (close(fd)) {
445 printerr("/dev/mem close failed: %s\n", strerror(errno));
446 free_fo(fo);
447 return NULL;
450 return fo;
453 /* Write fileobject contents to file */
454 static int write_file(const char *filename, const struct fileobject *fo)
456 FILE *fd_out = fopen(filename, "wb");
458 if (!fd_out) {
459 printerr("%s open failed: %s\n", filename, strerror(errno));
460 return 1;
462 if (fwrite(fo->data, 1, fo->size, fd_out) != fo->size) {
463 fclose(fd_out);
464 return 1;
466 return fclose(fd_out);
469 /* dump VBT contents in human readable form */
470 static void dump_vbt(const struct fileobject *fo)
472 if (fo->size < sizeof(struct vbt_header))
473 return;
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;
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);
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);
501 if (memcmp("BIOS_DATA_BLOCK ", bdb->signature, 16) != 0) {
502 printerr("invalid BDB signature:%s\n",
503 bdb->signature);
504 exit(1);
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;
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");
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;
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);
610 break;
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);
618 break;
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);
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;
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);
686 break;
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;
732 /* Returns a new fileobject containing a valid VBT */
733 static void parse_vbt(const struct fileobject *fo,
734 struct fileobject **vbt)
736 *vbt = NULL;
738 if (fo->size < sizeof(struct vbt_header)) {
739 printerr("image is too small\n");
740 return;
743 const struct vbt_header *head =
744 (const struct vbt_header *)fo->data;
746 if (memcmp(head->signature, "$VBT", 4) != 0) {
747 printerr("invalid VBT signature\n");
748 return;
751 if (!head->vbt_size || head->vbt_size > fo->size) {
752 printerr("invalid VBT size\n");
753 return;
756 if (!head->bdb_offset ||
757 head->bdb_offset > fo->size - sizeof(struct bdb_header)) {
758 printerr("invalid BDB offset\n");
759 return;
762 if (!head->header_size || head->header_size > fo->size) {
763 printerr("invalid header size\n");
764 return;
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;
774 if (!bdb_head->header_size || bdb_head->header_size > fo->size) {
775 printerr("invalid BDB header size\n");
776 return;
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;
786 struct fileobject *newfo = remalloc_fo(dupfo, head->vbt_size);
787 if (!newfo) {
788 printerr("remalloc failed\n");
789 free_fo(dupfo);
790 return;
793 *vbt = newfo;
796 /* Option ROM checksum */
797 static u8 checksum_vbios(const optionrom_header_t *oh)
799 const u8 *ptr = (const u8 *)oh;
800 size_t i;
802 u8 cksum = 0;
803 for (i = 0; i < ((MIN(oh->size, 128)) * 512); i++)
804 cksum += ptr[i];
806 return cksum;
809 /* Verify Option ROM contents */
810 static int is_valid_vbios(const struct fileobject *fo)
812 if (fo->size > 64 * 2 * KiB) {
813 printerr("VBIOS is too big\n");
814 return 0;
817 if (fo->size < sizeof(optionrom_header_t)) {
818 printerr("VBIOS is too small\n");
819 return 0;
822 const optionrom_header_t *oh = (const optionrom_header_t *)fo->data;
824 if (oh->signature != 0xaa55) {
825 printerr("bad oprom signature: 0x%x\n", oh->signature);
826 return 0;
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;
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;
840 printwarn("bad oprom checksum: 0x%x\n", cksum);
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;
848 if (oh->pcir_offset) {
849 const optionrom_pcir_t *pcir;
850 pcir = (const optionrom_pcir_t *)
851 ((const u8 *)oh + oh->pcir_offset);
853 if (pcir->signature != 0x52494350) {
854 printerr("Invalid PCIR signature\n");
855 return 0;
858 if (pcir->vendor != 0x8086) {
859 printerr("Not an Intel VBIOS\n");
860 return 0;
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;
868 } else {
869 printwarn("no PCIR header found\n");
872 return 1;
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.
880 static void parse_vbios(const struct fileobject *fo,
881 struct fileobject **vbt)
883 const optionrom_header_t *oh = (const optionrom_header_t *)fo->data;
884 size_t i;
886 *vbt = NULL;
888 if (!oh->vbt_offset) {
889 printerr("no VBT found\n");
890 return;
893 if (oh->vbt_offset > (fo->size - sizeof(struct vbt_header))) {
894 printerr("invalid VBT offset\n");
895 return;
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;
905 printwarn("VBT wasn't found at specified offset of %04x\n",
906 oh->vbt_offset);
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;
914 parse_vbt(fo_vbt, vbt);
916 free_fo(fo_vbt);
918 if (*vbt)
919 return;
923 /* Short VBT summary in human readable form */
924 static void print_vbt(const struct fileobject *fo)
926 const struct bdb_header *bdb;
928 if (fo->size < sizeof(struct vbt_header))
929 return;
931 const struct vbt_header *head = (const struct vbt_header *)fo->data;
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);
941 if (head->bdb_offset > (fo->size - sizeof(struct bdb_header))) {
942 printerr("invalid BDB offset\n");
943 return;
945 bdb = (const struct bdb_header *)
946 ((const char *)head + head->bdb_offset);
948 if (memcmp("BIOS_DATA_BLOCK ", bdb->signature, 16) != 0) {
949 printerr("invalid BDB signature:%s\n", bdb->signature);
950 return;
952 printt("BDB version: %u.%02u\n", bdb->version / 100,
953 bdb->version % 100);
956 static void print_usage(const char *argv0, struct option *long_options)
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");
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++;
980 /* Fix VBIOS header and PCIR */
981 static int fix_vbios_header(struct fileobject *fo)
983 if (!fo || fo->size < sizeof(optionrom_header_t))
984 return 1;
986 optionrom_header_t *oh = (optionrom_header_t *)fo->data;
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;
997 /* Fix size field */
998 oh->size = fo->size / 512;
1000 /* Fix checksum field */
1001 oh->checksum = -(checksum_vbios(oh) - oh->checksum);
1003 return 0;
1006 /* Return the VBT structure size in bytes */
1007 static size_t vbt_size(const struct fileobject *fo)
1009 if (!fo || fo->size < sizeof(struct vbt_header))
1010 return 0;
1011 const struct vbt_header *head = (const struct vbt_header *)fo->data;
1013 return head->vbt_size;
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.
1021 static int patch_vbios(struct fileobject *fo,
1022 const struct fileobject *fo_vbt)
1024 optionrom_header_t *oh = (optionrom_header_t *)fo->data;
1025 struct vbt_header *head;
1027 struct fileobject *old_vbt = NULL;
1028 parse_vbios(fo, &old_vbt);
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;
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;
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));
1056 free_fo(old_vbt);
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;
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;
1072 oh = (optionrom_header_t *)fo->data;
1075 head = (struct vbt_header *)((u8 *)oh + oh->vbt_offset);
1076 memcpy(head, fo_vbt->data, vbt_size(fo_vbt));
1078 return 0;
1081 int main(int argc, char **argv)
1083 int opt, ret, option_index = 0;
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}
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;
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;
1144 struct fileobject *fo;
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);
1153 if (!fo) {
1154 printerr("Failed to read input file\n");
1155 return 1;
1158 struct fileobject *vbt = NULL;
1159 if (in_legacy || in_oprom) {
1160 if (!is_valid_vbios(fo)) {
1161 printerr("Invalid input file\n");
1163 free_fo(fo);
1164 return 1;
1166 parse_vbios(fo, &vbt);
1167 } else
1168 parse_vbt(fo, &vbt);
1170 free_fo(fo);
1172 if (!vbt) {
1173 printerr("Failed to find VBT.\n");
1174 return 1;
1177 if (!dump)
1178 print_vbt(vbt);
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);
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;
1196 if (ret != 1 && !is_valid_vbios(fo)) {
1197 printerr("Invalid input file\n");
1198 ret = 1;
1200 if (ret != 1 && patch_vbios(fo, vbt)) {
1201 printerr("Failed to patch VBIOS\n");
1202 ret = 1;
1204 if (ret != 1 && fix_vbios_header(fo)) {
1205 printerr("Failed to fix VBIOS header\n");
1206 ret = 1;
1208 if (ret != 1 && write_file(patch_oprom, fo)) {
1209 printerr("Failed to write VBIOS\n");
1210 ret = 1;
1212 free_fo(fo);
1213 if (ret != 1)
1214 print("VBIOS %s successfully patched\n", patch_oprom);
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);
1227 free_fo(vbt);
1229 return ret;