xref: /aosp_15_r20/external/coreboot/util/intelvbttool/intelvbttool.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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 */
print(const char * format,...)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 
printt(const char * format,...)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 
printwarn(const char * format,...)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 
printerr(const char * format,...)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  */
malloc_fo(const size_t size)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 */
free_fo(struct fileobject * fo)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 */
remalloc_fo(struct fileobject * old,const size_t size)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  */
malloc_fo_sub(const struct fileobject * old,const size_t off)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 */
read_file(const char * filename)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 */
read_physmem(size_t addr)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 */
write_file(const char * filename,const struct fileobject * fo)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 */
dump_vbt(const struct fileobject * fo)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 */
parse_vbt(const struct fileobject * fo,struct fileobject ** 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 */
checksum_vbios(const optionrom_header_t * oh)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 */
is_valid_vbios(const struct fileobject * fo)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  */
parse_vbios(const struct fileobject * fo,struct fileobject ** vbt)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 */
print_vbt(const struct fileobject * fo)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 
print_usage(const char * argv0,struct option * long_options)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 */
fix_vbios_header(struct fileobject * fo)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 */
vbt_size(const struct fileobject * fo)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  */
patch_vbios(struct fileobject * fo,const struct fileobject * fo_vbt)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 
main(int argc,char ** argv)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 }
1231