Change-Id: I9fee87b7331ee05d4e984cb024f124abb2c97a69 Signed-off-by: Patrick Georgi <pgeorgi@chromium.org> Found-by: Coverity Scan #1347357 Reviewed-on: https://review.coreboot.org/15962 Tested-by: build bot (Jenkins) Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net> Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
		
			
				
	
	
		
			540 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			540 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (C) 2014 Vladimir Serbinenko
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or modify
 | 
						|
 * it under the terms of the GNU General Public License as published by
 | 
						|
 * the Free Software Foundation; version 2 of the License.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 * GNU General Public License for more details.
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <sys/mman.h>
 | 
						|
#include <stdint.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <fcntl.h>
 | 
						|
#include <errno.h>
 | 
						|
 | 
						|
typedef uint8_t u8;
 | 
						|
typedef uint16_t u16;
 | 
						|
typedef uint32_t u32;
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
	u16 signature;
 | 
						|
	u8 size;
 | 
						|
	u8 reserved[21];
 | 
						|
	u16 pcir_offset;
 | 
						|
	u16 vbt_offset;
 | 
						|
} __attribute__ ((packed)) optionrom_header_t;
 | 
						|
 | 
						|
struct vbt_header {
 | 
						|
	u8 signature[20];
 | 
						|
	u16 version;
 | 
						|
	u16 header_size;
 | 
						|
	u16 vbt_size;
 | 
						|
	u8 vbt_checksum;
 | 
						|
	u8 reserved0;
 | 
						|
	u32 bdb_offset;
 | 
						|
	u32 aim_offset[4];
 | 
						|
} __attribute__ ((packed));
 | 
						|
 | 
						|
struct bdb_header {
 | 
						|
	u8 signature[16];
 | 
						|
	u16 version;
 | 
						|
	u16 header_size;
 | 
						|
	u16 bdb_size;
 | 
						|
};
 | 
						|
 | 
						|
struct vbios_data {
 | 
						|
	u8 type;		/* 0 == desktop, 1 == mobile */
 | 
						|
	u8 relstage;
 | 
						|
	u8 chipset;
 | 
						|
	u8 lvds_present:1;
 | 
						|
	u8 tv_present:1;
 | 
						|
	u8 rsvd2:6;		/* finish byte */
 | 
						|
	u8 rsvd3[4];
 | 
						|
	u8 signon[155];
 | 
						|
	u8 copyright[61];
 | 
						|
	u16 code_segment;
 | 
						|
	u8 dos_boot_mode;
 | 
						|
	u8 bandwidth_percent;
 | 
						|
	u8 rsvd4;		/* popup memory size */
 | 
						|
	u8 resize_pci_bios;
 | 
						|
	u8 rsvd5;		/* is crt already on ddc2 */
 | 
						|
} __attribute__ ((packed));
 | 
						|
 | 
						|
struct bdb_general_features {
 | 
						|
	/* bits 1 */
 | 
						|
	u8 panel_fitting:2;
 | 
						|
	u8 flexaim:1;
 | 
						|
	u8 msg_enable:1;
 | 
						|
	u8 clear_screen:3;
 | 
						|
	u8 color_flip:1;
 | 
						|
 | 
						|
	/* bits 2 */
 | 
						|
	u8 download_ext_vbt:1;
 | 
						|
	u8 enable_ssc:1;
 | 
						|
	u8 ssc_freq:1;
 | 
						|
	u8 enable_lfp_on_override:1;
 | 
						|
	u8 disable_ssc_ddt:1;
 | 
						|
	u8 rsvd7:1;
 | 
						|
	u8 display_clock_mode:1;
 | 
						|
	u8 rsvd8:1;		/* finish byte */
 | 
						|
 | 
						|
	/* bits 3 */
 | 
						|
	u8 disable_smooth_vision:1;
 | 
						|
	u8 single_dvi:1;
 | 
						|
	u8 rsvd9:1;
 | 
						|
	u8 fdi_rx_polarity_inverted:1;
 | 
						|
	u8 rsvd10:4;		/* finish byte */
 | 
						|
 | 
						|
	/* bits 4 */
 | 
						|
	u8 legacy_monitor_detect;
 | 
						|
 | 
						|
	/* bits 5 */
 | 
						|
	u8 int_crt_support:1;
 | 
						|
	u8 int_tv_support:1;
 | 
						|
	u8 int_efp_support:1;
 | 
						|
	u8 dp_ssc_enb:1;	/* PCH attached eDP supports SSC */
 | 
						|
	u8 dp_ssc_freq:1;	/* SSC freq for PCH attached eDP */
 | 
						|
	u8 rsvd11:3;		/* finish byte */
 | 
						|
} __attribute__ ((packed));
 | 
						|
 | 
						|
struct common_child_dev_config {
 | 
						|
	u16 handle;
 | 
						|
	u16 device_type;
 | 
						|
	u8 not_common1[12];
 | 
						|
	u8 dvo_port;
 | 
						|
	u8 i2c_pin;
 | 
						|
	u8 slave_addr;
 | 
						|
	u8 ddc_pin;
 | 
						|
	u16 edid_ptr;
 | 
						|
	u8 not_common3[6];
 | 
						|
	u8 dvo_wiring;
 | 
						|
	u8 not_common4[4];
 | 
						|
} __attribute__ ((packed));
 | 
						|
 | 
						|
struct bdb_general_definitions {
 | 
						|
	/* DDC GPIO */
 | 
						|
	u8 crt_ddc_gmbus_pin;
 | 
						|
 | 
						|
	/* DPMS bits */
 | 
						|
	u8 dpms_acpi:1;
 | 
						|
	u8 skip_boot_crt_detect:1;
 | 
						|
	u8 dpms_aim:1;
 | 
						|
	u8 rsvd1:5;		/* finish byte */
 | 
						|
 | 
						|
	/* boot device bits */
 | 
						|
	u8 boot_display[2];
 | 
						|
	u8 child_dev_size;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Device info:
 | 
						|
	 * If TV is present, it'll be at devices[0].
 | 
						|
	 * LVDS will be next, either devices[0] or [1], if present.
 | 
						|
	 * On some platforms the number of device is 6. But could be as few as
 | 
						|
	 * 4 if both TV and LVDS are missing.
 | 
						|
	 * And the device num is related with the size of general definition
 | 
						|
	 * block. It is obtained by using the following formula:
 | 
						|
	 * number = (block_size - sizeof(bdb_general_definitions))/
 | 
						|
	 *           sizeof(child_device_config);
 | 
						|
	 */
 | 
						|
	struct common_child_dev_config devices[0];
 | 
						|
} __attribute__ ((packed));
 | 
						|
 | 
						|
struct bdb_driver_features {
 | 
						|
	u8 boot_dev_algorithm:1;
 | 
						|
	u8 block_display_switch:1;
 | 
						|
	u8 allow_display_switch:1;
 | 
						|
	u8 hotplug_dvo:1;
 | 
						|
	u8 dual_view_zoom:1;
 | 
						|
	u8 int15h_hook:1;
 | 
						|
	u8 sprite_in_clone:1;
 | 
						|
	u8 primary_lfp_id:1;
 | 
						|
 | 
						|
	u16 boot_mode_x;
 | 
						|
	u16 boot_mode_y;
 | 
						|
	u8 boot_mode_bpp;
 | 
						|
	u8 boot_mode_refresh;
 | 
						|
 | 
						|
	u16 enable_lfp_primary:1;
 | 
						|
	u16 selective_mode_pruning:1;
 | 
						|
	u16 dual_frequency:1;
 | 
						|
	u16 render_clock_freq:1;	/* 0: high freq; 1: low freq */
 | 
						|
	u16 nt_clone_support:1;
 | 
						|
	u16 power_scheme_ui:1;	/* 0: CUI; 1: 3rd party */
 | 
						|
	u16 sprite_display_assign:1;	/* 0: secondary; 1: primary */
 | 
						|
	u16 cui_aspect_scaling:1;
 | 
						|
	u16 preserve_aspect_ratio:1;
 | 
						|
	u16 sdvo_device_power_down:1;
 | 
						|
	u16 crt_hotplug:1;
 | 
						|
	u16 lvds_config:2;
 | 
						|
	u16 tv_hotplug:1;
 | 
						|
	u16 hdmi_config:2;
 | 
						|
 | 
						|
	u8 static_display:1;
 | 
						|
	u8 reserved2:7;
 | 
						|
	u16 legacy_crt_max_x;
 | 
						|
	u16 legacy_crt_max_y;
 | 
						|
	u8 legacy_crt_max_refresh;
 | 
						|
 | 
						|
	u8 hdmi_termination;
 | 
						|
	u8 custom_vbt_version;
 | 
						|
} __attribute__ ((packed));
 | 
						|
 | 
						|
struct bdb_lvds_options {
 | 
						|
	u8 panel_type;
 | 
						|
	u8 rsvd1;
 | 
						|
	/* LVDS capabilities, stored in a dword */
 | 
						|
	u8 pfit_mode:2;
 | 
						|
	u8 pfit_text_mode_enhanced:1;
 | 
						|
	u8 pfit_gfx_mode_enhanced:1;
 | 
						|
	u8 pfit_ratio_auto:1;
 | 
						|
	u8 pixel_dither:1;
 | 
						|
	u8 lvds_edid:1;
 | 
						|
	u8 rsvd2:1;
 | 
						|
	u8 rsvd4;
 | 
						|
} __attribute__ ((packed));
 | 
						|
 | 
						|
struct bdb_sdvo_lvds_options {
 | 
						|
	u8 panel_backlight;
 | 
						|
	u8 h40_set_panel_type;
 | 
						|
	u8 panel_type;
 | 
						|
	u8 ssc_clk_freq;
 | 
						|
	u16 als_low_trip;
 | 
						|
	u16 als_high_trip;
 | 
						|
	u8 sclalarcoeff_tab_row_num;
 | 
						|
	u8 sclalarcoeff_tab_row_size;
 | 
						|
	u8 coefficient[8];
 | 
						|
	u8 panel_misc_bits_1;
 | 
						|
	u8 panel_misc_bits_2;
 | 
						|
	u8 panel_misc_bits_3;
 | 
						|
	u8 panel_misc_bits_4;
 | 
						|
} __attribute__ ((packed));
 | 
						|
 | 
						|
 | 
						|
#define BDB_GENERAL_FEATURES	  1
 | 
						|
#define BDB_GENERAL_DEFINITIONS	  2
 | 
						|
 | 
						|
#define BDB_DRIVER_FEATURES	 12
 | 
						|
#define BDB_SDVO_LVDS_OPTIONS	 22
 | 
						|
#define BDB_SDVO_PANEL_DTDS	 23
 | 
						|
#define BDB_LVDS_OPTIONS	 40
 | 
						|
#define BDB_LVDS_LFP_DATA_PTRS	 41
 | 
						|
#define BDB_LVDS_LFP_DATA	 42
 | 
						|
 | 
						|
#define BDB_SKIP		254
 | 
						|
 | 
						|
static void parse_vbt(const void *vbt)
 | 
						|
{
 | 
						|
	const struct vbt_header *head = vbt;
 | 
						|
	const struct bdb_header *bdb;
 | 
						|
	int i;
 | 
						|
	const u8 *ptr;
 | 
						|
	int is_first_skip = 1;
 | 
						|
 | 
						|
	if (memcmp(head->signature, "$VBT", 4) != 0) {
 | 
						|
		fprintf(stderr, "invalid VBT signature\n");
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
	printf("signature: <%20.20s>\n", head->signature);
 | 
						|
	printf("version: %d.%02d\n", head->version / 100,
 | 
						|
	       head->version % 100);
 | 
						|
	if (head->header_size != sizeof(struct vbt_header))
 | 
						|
		printf("header size: 0x%x\n", head->header_size);
 | 
						|
	printf("VBT size: 0x%x\n", head->vbt_size);
 | 
						|
	printf("VBT checksum: 0x%x\n", head->vbt_checksum);
 | 
						|
	if (head->reserved0)
 | 
						|
		printf("header reserved0: 0x%x\n", head->reserved0);
 | 
						|
	if (head->bdb_offset != sizeof(struct vbt_header))
 | 
						|
		printf("BDB offset: 0x%x\n", head->bdb_offset);
 | 
						|
 | 
						|
	for (i = 0; i < 4; i++)
 | 
						|
		if (head->aim_offset[i])
 | 
						|
			printf("AIM[%d] offset: 0x%x\n", i,
 | 
						|
			       head->aim_offset[i]);
 | 
						|
	bdb = (const void *) ((const char *) vbt + head->bdb_offset);
 | 
						|
 | 
						|
	if (memcmp("BIOS_DATA_BLOCK ", bdb->signature, 16) != 0) {
 | 
						|
		fprintf(stderr, "invalid BDB signature:%s\n",
 | 
						|
			bdb->signature);
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
	printf("BDB version: %d.%02d\n", bdb->version / 100,
 | 
						|
	       bdb->version % 100);
 | 
						|
	if (bdb->header_size != sizeof(struct bdb_header))
 | 
						|
		printf("BDB header size: 0x%x\n", bdb->header_size);
 | 
						|
	if (bdb->bdb_size != head->vbt_size - head->bdb_offset)
 | 
						|
		printf("BDB size: 0x%x\n", bdb->bdb_size);
 | 
						|
	for (ptr = (const u8 *) bdb + bdb->header_size;
 | 
						|
	     ptr < (const u8 *) bdb + bdb->bdb_size;) {
 | 
						|
		u16 secsz = (ptr[1] | (ptr[2] << 8));
 | 
						|
		u8 sectype = ptr[0];
 | 
						|
		const u8 *section = ptr + 3;
 | 
						|
 | 
						|
		printf("section type %d, size 0x%x\n", sectype, secsz);
 | 
						|
		ptr += secsz + 3;
 | 
						|
		switch (sectype) {
 | 
						|
		case BDB_GENERAL_FEATURES:{
 | 
						|
				const struct bdb_general_features *sec =
 | 
						|
				    (const void *) section;
 | 
						|
				printf("General features:\n");
 | 
						|
 | 
						|
				if (sec->panel_fitting)
 | 
						|
					printf("\tpanel_fitting = 0x%x\n",
 | 
						|
					       sec->panel_fitting);
 | 
						|
				if (sec->flexaim)
 | 
						|
					printf("\tflexaim = 0x%x\n",
 | 
						|
					       sec->flexaim);
 | 
						|
				if (sec->msg_enable)
 | 
						|
					printf("\tmsg_enable = 0x%x\n",
 | 
						|
					       sec->msg_enable);
 | 
						|
				if (sec->clear_screen)
 | 
						|
					printf("\tclear_screen = 0x%x\n",
 | 
						|
					       sec->clear_screen);
 | 
						|
				if (sec->color_flip)
 | 
						|
					printf("\tcolor_flip = 0x%x\n",
 | 
						|
					       sec->color_flip);
 | 
						|
				if (sec->download_ext_vbt)
 | 
						|
					printf
 | 
						|
					    ("\tdownload_ext_vbt = 0x%x\n",
 | 
						|
					     sec->download_ext_vbt);
 | 
						|
				printf("\t*enable_ssc = 0x%x\n",
 | 
						|
				       sec->enable_ssc);
 | 
						|
				printf("\t*ssc_freq = 0x%x\n",
 | 
						|
				       sec->ssc_freq);
 | 
						|
				if (sec->enable_lfp_on_override)
 | 
						|
					printf
 | 
						|
					    ("\tenable_lfp_on_override = 0x%x\n",
 | 
						|
					     sec->enable_lfp_on_override);
 | 
						|
				if (sec->disable_ssc_ddt)
 | 
						|
					printf
 | 
						|
					    ("\tdisable_ssc_ddt = 0x%x\n",
 | 
						|
					     sec->disable_ssc_ddt);
 | 
						|
				if (sec->rsvd7)
 | 
						|
					printf("\trsvd7 = 0x%x\n",
 | 
						|
					       sec->rsvd7);
 | 
						|
				printf("\t*display_clock_mode = 0x%x\n",
 | 
						|
				       sec->display_clock_mode);
 | 
						|
				if (sec->rsvd8)
 | 
						|
					printf("\trsvd8 = 0x%x\n",
 | 
						|
					       sec->rsvd8);
 | 
						|
				printf("\tdisable_smooth_vision = 0x%x\n",
 | 
						|
				       sec->disable_smooth_vision);
 | 
						|
				if (sec->single_dvi)
 | 
						|
					printf("\tsingle_dvi = 0x%x\n",
 | 
						|
					       sec->single_dvi);
 | 
						|
				if (sec->rsvd9)
 | 
						|
					printf("\trsvd9 = 0x%x\n",
 | 
						|
					       sec->rsvd9);
 | 
						|
				printf
 | 
						|
				    ("\t*fdi_rx_polarity_inverted = 0x%x\n",
 | 
						|
				     sec->fdi_rx_polarity_inverted);
 | 
						|
				if (sec->rsvd10)
 | 
						|
					printf("\trsvd10 = 0x%x\n",
 | 
						|
					       sec->rsvd10);
 | 
						|
				if (sec->legacy_monitor_detect)
 | 
						|
					printf
 | 
						|
					    ("\tlegacy_monitor_detect = 0x%x\n",
 | 
						|
					     sec->legacy_monitor_detect);
 | 
						|
				printf("\t*int_crt_support = 0x%x\n",
 | 
						|
				       sec->int_crt_support);
 | 
						|
				printf("\t*int_tv_support = 0x%x\n",
 | 
						|
				       sec->int_tv_support);
 | 
						|
				if (sec->int_efp_support)
 | 
						|
					printf
 | 
						|
					    ("\tint_efp_support = 0x%x\n",
 | 
						|
					     sec->int_efp_support);
 | 
						|
				if (sec->dp_ssc_enb)
 | 
						|
					printf("\tdp_ssc_enb = 0x%x\n",
 | 
						|
					       sec->dp_ssc_enb);
 | 
						|
				if (sec->dp_ssc_freq)
 | 
						|
					printf("\tdp_ssc_freq = 0x%x\n",
 | 
						|
					       sec->dp_ssc_freq);
 | 
						|
				if (sec->rsvd11)
 | 
						|
					printf("\trsvd11 = 0x%x\n",
 | 
						|
					       sec->rsvd11);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		case BDB_DRIVER_FEATURES:{
 | 
						|
				const struct bdb_driver_features *sec =
 | 
						|
				    (const void *) section;
 | 
						|
				printf("\t*LVDS config: %d\n",
 | 
						|
				       sec->lvds_config);
 | 
						|
				printf("\t*Dual frequency: %d\n",
 | 
						|
				       sec->dual_frequency);
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		case BDB_SDVO_LVDS_OPTIONS:{
 | 
						|
				const struct bdb_sdvo_lvds_options *sec =
 | 
						|
				    (const void *) section;
 | 
						|
				printf("\t*Panel type: %d\n",
 | 
						|
				       sec->panel_type);
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		case BDB_GENERAL_DEFINITIONS:{
 | 
						|
				const struct bdb_general_definitions *sec =
 | 
						|
				    (const void *) section;
 | 
						|
				int ndev;
 | 
						|
				printf("\t*CRT DDC GMBUS pin: %d\n",
 | 
						|
				       sec->crt_ddc_gmbus_pin);
 | 
						|
 | 
						|
				printf("\tDPMS ACPI: %d\n",
 | 
						|
				       sec->dpms_acpi);
 | 
						|
				printf("\tSkip boot CRT detect: %d\n",
 | 
						|
				       sec->skip_boot_crt_detect);
 | 
						|
				printf("\tDPMS aim: %d\n", sec->dpms_aim);
 | 
						|
				if (sec->rsvd1)
 | 
						|
					printf("\trsvd1: 0x%x\n",
 | 
						|
					       sec->rsvd1);
 | 
						|
				printf("\tboot_display: { %x, %x }\n",
 | 
						|
				       sec->boot_display[0],
 | 
						|
				       sec->boot_display[1]);
 | 
						|
				if (sec->child_dev_size !=
 | 
						|
				    sizeof(struct common_child_dev_config))
 | 
						|
					printf("\tchild_dev_size: %d\n",
 | 
						|
					       sec->child_dev_size);
 | 
						|
				ndev = (secsz - sizeof(*sec)) /
 | 
						|
					sizeof(struct common_child_dev_config);
 | 
						|
				printf("\t%d devices\n", ndev);
 | 
						|
				for (i = 0; i < ndev; i++) {
 | 
						|
					printf("\t*device type: %x ",
 | 
						|
					       sec->devices[i].
 | 
						|
					       device_type);
 | 
						|
#define	 DEVICE_TYPE_INT_LFP	0x1022
 | 
						|
#define	 DEVICE_TYPE_INT_TV	0x1009
 | 
						|
#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR	0x6052
 | 
						|
					switch (sec->devices[i].device_type) {
 | 
						|
					case DEVICE_TYPE_INT_LFP:
 | 
						|
						printf("(flat panel)\n");
 | 
						|
						break;
 | 
						|
					case DEVICE_TYPE_INT_TV:
 | 
						|
						printf("(TV)\n");
 | 
						|
						break;
 | 
						|
					case DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR:
 | 
						|
						printf
 | 
						|
						    ("(DVI)\n");
 | 
						|
						break;
 | 
						|
					case 0:
 | 
						|
						printf("(Empty)\n");
 | 
						|
						break;
 | 
						|
					default:
 | 
						|
						printf("(Unknown)\n");
 | 
						|
						break;
 | 
						|
					}
 | 
						|
					if (!sec->devices[i].device_type)
 | 
						|
						continue;
 | 
						|
					printf("\t *dvo_port: %x\n",
 | 
						|
					       sec->devices[i].dvo_port);
 | 
						|
					printf("\t *i2c_pin: %x\n",
 | 
						|
					       sec->devices[i].i2c_pin);
 | 
						|
					printf("\t *slave_addr: %x\n",
 | 
						|
					       sec->devices[i].slave_addr);
 | 
						|
					printf("\t *ddc_pin: %x\n",
 | 
						|
					       sec->devices[i].ddc_pin);
 | 
						|
					printf("\t *dvo_wiring: %x\n",
 | 
						|
					       sec->devices[i].dvo_wiring);
 | 
						|
					printf("\t edid_ptr: %x\n",
 | 
						|
					       sec->devices[i].edid_ptr);
 | 
						|
				}
 | 
						|
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		case BDB_SKIP:{
 | 
						|
				const struct vbios_data *sec =
 | 
						|
				    (const void *) section;
 | 
						|
				if (!is_first_skip)
 | 
						|
					break;
 | 
						|
				is_first_skip = 0;
 | 
						|
				printf("\ttype: %x\n", sec->type);
 | 
						|
				printf("\trelstage: %x\n", sec->relstage);
 | 
						|
				printf("\tchipset: %x\n", sec->chipset);
 | 
						|
				printf(sec->lvds_present ? "\tLVDS\n"
 | 
						|
				       : "\tNo LVDS\n");
 | 
						|
				printf(sec->tv_present ? "\tTV\n"
 | 
						|
				       : "\tNo TV\n");
 | 
						|
				if (sec->rsvd2)
 | 
						|
					printf("\trsvd2: 0x%x\n",
 | 
						|
					       sec->rsvd2);
 | 
						|
				for (i = 0; i < 4; i++)
 | 
						|
					if (sec->rsvd3[i])
 | 
						|
						printf
 | 
						|
						    ("\trsvd3[%d]: 0x%x\n",
 | 
						|
						     i, sec->rsvd3[i]);
 | 
						|
				printf("\tSignon: %.155s\n", sec->signon);
 | 
						|
				printf("\tCopyright: %.155s\n",
 | 
						|
				       sec->copyright);
 | 
						|
				printf("\tCode segment: %x\n",
 | 
						|
				       sec->code_segment);
 | 
						|
				printf("\tDOS Boot mode: %x\n",
 | 
						|
				       sec->dos_boot_mode);
 | 
						|
				printf("\tBandwidth percent: %x\n",
 | 
						|
				       sec->bandwidth_percent);
 | 
						|
				if (sec->rsvd4)
 | 
						|
					printf("\trsvd4: 0x%x\n",
 | 
						|
					       sec->rsvd4);
 | 
						|
				printf("\tBandwidth percent: %x\n",
 | 
						|
				       sec->resize_pci_bios);
 | 
						|
				if (sec->rsvd5)
 | 
						|
					printf("\trsvd5: 0x%x\n",
 | 
						|
					       sec->rsvd5);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void parse_vbios(const void *ptr)
 | 
						|
{
 | 
						|
	const optionrom_header_t *oh;
 | 
						|
	oh = ptr;
 | 
						|
	if (oh->signature != 0xaa55) {
 | 
						|
		fprintf(stderr, "bad oprom signature: %x\n",
 | 
						|
			oh->signature);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	if (!oh->vbt_offset) {
 | 
						|
		fprintf(stderr, "no VBT found\n");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	parse_vbt((const char *) ptr + oh->vbt_offset);
 | 
						|
}
 | 
						|
 | 
						|
int main(int argc, char **argv)
 | 
						|
{
 | 
						|
	const void *ptr;
 | 
						|
	int fd;
 | 
						|
	off_t offset;
 | 
						|
	if (argc == 2) {
 | 
						|
		fd = open(argv[1], O_RDONLY);
 | 
						|
		offset = 0;
 | 
						|
	} else {
 | 
						|
		fd = open("/dev/mem", O_RDONLY);
 | 
						|
		offset = 0xc0000;
 | 
						|
	}
 | 
						|
	if (fd < 0) {
 | 
						|
		fprintf(stderr, "open failed: %s\n", strerror(errno));
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
 | 
						|
	ptr = mmap(0, 65536, PROT_READ, MAP_SHARED, fd, offset);
 | 
						|
	if (ptr == MAP_FAILED) {
 | 
						|
		fprintf(stderr, "mmap failed: %s\n", strerror(errno));
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
	parse_vbios(ptr);
 | 
						|
	close(fd);
 | 
						|
	return 0;
 | 
						|
}
 |