[flashrom] [PATCH 3/4] add ICH/PCH flash descriptor decoding

Stefan Tauner stefan.tauner at student.tuwien.ac.at
Sun Jun 26 06:22:56 CEST 2011


based on the work of Matthias 'mazzoo' Wenzel this patch adds...
 - pretty printing of those ICH/PCH flash descriptors that are cached/mapped
   by the chipset (and which are therefore reachable via FDOC/FDOD
   registers)
 - a new tool to the util directory that is able to decode all flash
   descriptors stored in a flash dump file.

it also adds macros and pretty printing for "Vendor Specific
Component Capabilities" registers:
there are two of them: lower and upper. they describe the properties
of the address space divided by FPBA (which allows to use multiple
flash chips or partitions with different properties). the
prettyprinting function is used by the descriptor code too: the
properties of flash chips supported by the ME are stored in the same
format in a descriptor table. this is also the reason why the pp
function and the register bit macros are not defined in ichspi.c but
ich_descriptors.h

TODO:
- is endianess important? and other questions related to the
  struct/union pattern used.
- how to detect the chipset used for the strap descriptors which
  differ a lot between chipset versions? when called from flashrom
  this is easy (1. because we know the chipset and 2. we don't need
  to know currently, because we can't read it via registers anyway.
  do we wanna try to read the descriptor block from flash for this?).
  there is afaics no way to deduce the chipset from image files so
  we should introduce a parameter for that in the tool...?
- file naming and partitioning was not discussed. we may want a ichspi.h.
  and/or rename ichspi.c to ich_spi.c or similar...

Signed-off-by: Stefan Tauner <stefan.tauner at student.tuwien.ac.at>
---
 Makefile                                         |    3 +-
 ich_descriptors.c                                |  490 ++++++++++++++++++++++
 ich_descriptors.h                                |  447 ++++++++++++++++++++
 ichspi.c                                         |   35 ++-
 util/ich_descriptors_tool/Makefile               |   42 ++
 util/ich_descriptors_tool/TODO                   |    5 +
 util/ich_descriptors_tool/ich_descriptors_tool.c |  226 ++++++++++
 7 files changed, 1243 insertions(+), 5 deletions(-)
 create mode 100644 ich_descriptors.c
 create mode 100644 ich_descriptors.h
 create mode 100644 util/ich_descriptors_tool/Makefile
 create mode 100644 util/ich_descriptors_tool/TODO
 create mode 100644 util/ich_descriptors_tool/ich_descriptors_tool.c

diff --git a/Makefile b/Makefile
index 6e6e2de..8679f00 100644
--- a/Makefile
+++ b/Makefile
@@ -223,7 +223,8 @@ ifeq ($(CONFIG_INTERNAL), yes)
 FEATURE_CFLAGS += -D'CONFIG_INTERNAL=1'
 PROGRAMMER_OBJS += processor_enable.o chipset_enable.o board_enable.o cbtable.o dmi.o internal.o
 # FIXME: The PROGRAMMER_OBJS below should only be included on x86.
-PROGRAMMER_OBJS += it87spi.o it85spi.o ichspi.o sb600spi.o wbsio_spi.o mcp6x_spi.o
+PROGRAMMER_OBJS += it87spi.o it85spi.o sb600spi.o wbsio_spi.o mcp6x_spi.o
+PROGRAMMER_OBJS += ichspi.o ich_descriptors.o
 NEED_PCI := yes
 endif
 
diff --git a/ich_descriptors.c b/ich_descriptors.c
new file mode 100644
index 0000000..1b7dc36
--- /dev/null
+++ b/ich_descriptors.c
@@ -0,0 +1,490 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (c) 2010  Matthias Wenzel <bios at mazzoo dot de>
+ * Copyright (c) 2011  Stefan Tauner
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "ich_descriptors.h"
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#ifdef ICH_DESCRIPTORS_FROM_MMAP_DUMP
+
+#define DESCRIPTOR_MODE_MAGIC 0x0ff0a55a
+#define msg_pdbg printf
+#define msg_perr printf
+#include <stdio.h>
+
+struct flash_strap fisba;
+struct flash_upper_map flumap;
+
+#else
+
+#include "flash.h" /* for msg_* */
+
+#endif // ICH_DESCRIPTORS_FROM_MMAP_DUMP
+
+struct flash_descriptor fdbar = { 0 };
+struct flash_component fcba = { {0} };
+struct flash_region frba = { {0} };
+struct flash_master fmba = { {0} };
+
+uint32_t getFCBA(void)
+{
+	return (fdbar.FLMAP0 <<  4) & 0x00000ff0;
+}
+
+uint32_t getFRBA(void)
+{
+	return (fdbar.FLMAP0 >> 12) & 0x00000ff0;
+}
+
+uint32_t getFMBA(void)
+{
+	return (fdbar.FLMAP1 <<  4) & 0x00000ff0;
+}
+
+uint32_t getFMSBA(void)
+{
+	return (fdbar.FLMAP2 <<  4) & 0x00000ff0;
+}
+
+uint32_t getFLREG_limit(uint32_t flreg)
+{
+	return (flreg >>  4) & 0x01fff000;
+}
+
+uint32_t getFLREG_base(uint32_t flreg)
+{
+	return (flreg << 12) & 0x01fff000;
+}
+
+uint32_t getFISBA(void)
+{
+	return (fdbar.FLMAP1 >> 12) & 0x00000ff0;
+}
+
+/** Returns the integer representation of the component density with index
+comp in bytes or 0 if a correct size can not be determined. */
+int getFCBA_component_density(uint8_t comp)
+{
+	uint8_t size_enc;
+	const int dec_mem[6] = {
+		      512 * 1024,
+		 1 * 1024 * 1024,
+		 2 * 1024 * 1024,
+		 4 * 1024 * 1024,
+		 8 * 1024 * 1024,
+		16 * 1024 * 1024,
+	};
+
+	switch(comp) {
+	case 0:
+		size_enc = fcba.comp1_density;
+		break;
+	case 1:
+		if (fdbar.NC == 0)
+			return 0;
+		size_enc = fcba.comp2_density;
+		break;
+	default:
+		msg_perr("Only component index 0 or 1 are supported yet.\n");
+		return 0;
+	}
+	if (size_enc > 5) {
+		msg_perr("Density of component with index %d illegal or "
+			 "unsupported. Encoded density is 0x%x.\n", comp,
+			 size_enc);
+		return 0;
+	}
+	return dec_mem[size_enc];
+}
+
+#ifdef ICH_DESCRIPTORS_FROM_MMAP_DUMP
+uint32_t getVTBA(void)
+{	/* The bits in FLUMAP1 describe bits 4-11 out of 24 in total;
+	 * others are 0. */
+	return (flumap.FLUMAP1 << 4) & 0x0ff0;
+}
+#endif
+
+const struct flash_descriptor_addresses desc_addr = {
+	.FCBA = getFCBA,
+	.FRBA = getFRBA,
+	.FMBA = getFMBA,
+	.FMSBA = getFMSBA,
+	.FISBA = getFISBA,
+	.FLREG_limit = getFLREG_limit,
+	.FLREG_base = getFLREG_base,
+#ifdef ICH_DESCRIPTORS_FROM_MMAP_DUMP
+	.VTBA = getVTBA,
+#endif
+};
+
+void prettyprint_ich_descriptors(void)
+{
+	prettyprint_ich_descriptor_map();
+	prettyprint_ich_descriptor_component();
+	prettyprint_ich_descriptor_region();
+	prettyprint_ich_descriptor_master();
+#ifdef ICH_DESCRIPTORS_FROM_MMAP_DUMP
+	prettyprint_ich_descriptor_upper_map();
+	/* FIXME: detect chipset correctly */
+	prettyprint_ich_descriptor_straps(CHIPSET_SERIES_5_IBEX_PEAK);
+#endif // ICH_DESCRIPTORS_FROM_MMAP_DUMP
+	msg_pdbg("\n");
+}
+
+void prettyprint_ich_descriptor_map(void)
+{
+	msg_pdbg("=== FDBAR ===\n");
+	msg_pdbg("FLVALSIG 0x%8.8x\n", fdbar.FLVALSIG);
+	msg_pdbg("FLMAP0   0x%8.8x\n", fdbar.FLMAP0  );
+	msg_pdbg("FLMAP1   0x%8.8x\n", fdbar.FLMAP1  );
+	msg_pdbg("FLMAP2   0x%8.8x\n", fdbar.FLMAP2  );
+	msg_pdbg("\n");
+	msg_pdbg("--- FDBAR details ---\n");
+	msg_pdbg("0x%2.2x        NR    Number of Regions\n", fdbar.NR   );
+	msg_pdbg("0x%8.8x  FRBA  Flash Region Base Address\n", desc_addr.FRBA() );
+	msg_pdbg("0x%2.2x        NC    Number of Components\n", fdbar.NC   );
+	msg_pdbg("0x%8.8x  FCBA  Flash Component Base Address\n", desc_addr.FCBA() );
+	msg_pdbg("\n");
+	msg_pdbg("0x%2.2x        ISL   ICH Strap Length\n", fdbar.ISL  );
+	msg_pdbg("0x%8.8x  FISBA Flash ICH Strap Base Address\n", desc_addr.FISBA());
+	msg_pdbg("0x%2.2x        NM    Number of Masters\n", fdbar.NM   );
+	msg_pdbg("0x%8.8x  FMBA  Flash Master Base Address\n", desc_addr.FMBA() );
+	msg_pdbg("\n");
+	msg_pdbg("0x%2.2x        MSL   MCH Strap Length\n", fdbar.MSL  );
+	msg_pdbg("0x%8.8x  FMSBA Flash MCH Strap Base Address\n", desc_addr.FMSBA());
+}
+
+void prettyprint_ich_descriptor_component(void)
+{
+	const char * const str_freq[8] = {
+		"20 MHz",		/* 000 */
+		"33 MHz",		/* 001 */
+		"reserved/illegal",	/* 010 */
+		"reserved/illegal",	/* 011 */
+		"50 MHz",		/* 100 */
+		"reserved/illegal",	/* 101 */
+		"reserved/illegal",	/* 110 */
+		"reserved/illegal"	/* 111 */
+	};
+	const char * const str_mem[8] = {
+		"512kB",
+		"1 MB",
+		"2 MB",
+		"4 MB",
+		"8 MB",
+		"16 MB",
+		"undocumented/illegal",
+		"reserved/illegal"
+	};
+
+	msg_pdbg("\n");
+	msg_pdbg("=== FCBA ===\n");
+	msg_pdbg("FLCOMP   0x%8.8x\n", fcba.FLCOMP);
+	msg_pdbg("FLILL    0x%8.8x\n", fcba.FLILL );
+	msg_pdbg("\n");
+	msg_pdbg("--- FCBA details ---\n");
+	msg_pdbg("0x%2.2x    freq_read_id   %s\n",
+		fcba.freq_read_id , str_freq[fcba.freq_read_id ]);
+	msg_pdbg("0x%2.2x    freq_write     %s\n",
+		fcba.freq_write   , str_freq[fcba.freq_write   ]);
+	msg_pdbg("0x%2.2x    freq_fastread  %s\n",
+		fcba.freq_fastread, str_freq[fcba.freq_fastread]);
+	msg_pdbg("0x%2.2x    fastread       %ssupported\n",
+		fcba.fastread, fcba.fastread ? "" : "not ");
+	msg_pdbg("0x%2.2x    freq_read      %s\n",
+		fcba.freq_read, str_freq[fcba.freq_read    ]);
+	msg_pdbg("0x%2.2x    comp 1 density %s\n",
+		fcba.comp1_density, str_mem[fcba.comp1_density]);
+	if (fdbar.NC)
+		msg_pdbg("0x%2.2x    comp 2 density %s\n",
+			fcba.comp2_density, str_mem[fcba.comp2_density]);
+	else
+		msg_pdbg("0x%2.2x    comp 2 is not used (FLMAP0.NC=0)\n",
+			fcba.comp2_density);
+	msg_pdbg("\n");
+	msg_pdbg("0x%2.2x    invalid instr 0\n", fcba.invalid_instr0);
+	msg_pdbg("0x%2.2x    invalid instr 1\n", fcba.invalid_instr1);
+	msg_pdbg("0x%2.2x    invalid instr 2\n", fcba.invalid_instr2);
+	msg_pdbg("0x%2.2x    invalid instr 3\n", fcba.invalid_instr3);
+}
+
+void prettyprint_ich_descriptor_region(void)
+{
+	msg_pdbg("\n");
+	msg_pdbg("=== FRBA ===\n");
+	msg_pdbg("FLREG0   0x%8.8x\n", frba.FLREG0);
+	msg_pdbg("FLREG1   0x%8.8x\n", frba.FLREG1);
+	msg_pdbg("FLREG2   0x%8.8x\n", frba.FLREG2);
+	msg_pdbg("FLREG3   0x%8.8x\n", frba.FLREG3);
+	msg_pdbg("\n");
+	msg_pdbg("--- FRBA details ---\n");
+	msg_pdbg("0x%8.8x  region 0 limit (descr)\n", desc_addr.FLREG_limit(frba.FLREG0));
+	msg_pdbg("0x%8.8x  region 0 base  (descr)\n", desc_addr.FLREG_base(frba.FLREG0));
+	msg_pdbg("0x%8.8x  region 1 limit ( BIOS)\n", desc_addr.FLREG_limit(frba.FLREG1));
+	msg_pdbg("0x%8.8x  region 1 base  ( BIOS)\n", desc_addr.FLREG_base(frba.FLREG1));
+	msg_pdbg("0x%8.8x  region 2 limit ( ME  )\n", desc_addr.FLREG_limit(frba.FLREG2));
+	msg_pdbg("0x%8.8x  region 2 base  ( ME  )\n", desc_addr.FLREG_base(frba.FLREG2));
+	msg_pdbg("0x%8.8x  region 3 limit ( GbE )\n", desc_addr.FLREG_limit(frba.FLREG3));
+	msg_pdbg("0x%8.8x  region 3 base  ( GbE )\n", desc_addr.FLREG_base(frba.FLREG3));
+}
+
+void prettyprint_ich_descriptor_master(void)
+{
+	msg_pdbg("\n");
+	msg_pdbg("=== FMBA ===\n");
+	msg_pdbg("FLMSTR1  0x%8.8x\n", fmba.FLMSTR1);
+	msg_pdbg("FLMSTR2  0x%8.8x\n", fmba.FLMSTR2);
+	msg_pdbg("FLMSTR3  0x%8.8x\n", fmba.FLMSTR3);
+
+	msg_pdbg("\n");
+	msg_pdbg("--- FMBA details ---\n");
+	msg_pdbg("BIOS can %s write GbE\n",   fmba.BIOS_GbE_write   ? "   " : "NOT");
+	msg_pdbg("BIOS can %s write ME\n",    fmba.BIOS_ME_write    ? "   " : "NOT");
+	msg_pdbg("BIOS can %s write BIOS\n",  fmba.BIOS_BIOS_write  ? "   " : "NOT");
+	msg_pdbg("BIOS can %s write descr\n", fmba.BIOS_descr_write ? "   " : "NOT");
+	msg_pdbg("BIOS can %s read  GbE\n",   fmba.BIOS_GbE_read    ? "   " : "NOT");
+	msg_pdbg("BIOS can %s read  ME\n",    fmba.BIOS_ME_read     ? "   " : "NOT");
+	msg_pdbg("BIOS can %s read  BIOS\n",  fmba.BIOS_BIOS_read   ? "   " : "NOT");
+	msg_pdbg("BIOS can %s read  descr\n", fmba.BIOS_descr_read  ? "   " : "NOT");
+	msg_pdbg("ME   can %s write GbE\n",   fmba.ME_GbE_write     ? "   " : "NOT");
+	msg_pdbg("ME   can %s write ME\n",    fmba.ME_ME_write      ? "   " : "NOT");
+	msg_pdbg("ME   can %s write BIOS\n",  fmba.ME_BIOS_write    ? "   " : "NOT");
+	msg_pdbg("ME   can %s write descr\n", fmba.ME_descr_write   ? "   " : "NOT");
+	msg_pdbg("ME   can %s read  GbE\n",   fmba.ME_GbE_read      ? "   " : "NOT");
+	msg_pdbg("ME   can %s read  ME\n",    fmba.ME_ME_read       ? "   " : "NOT");
+	msg_pdbg("ME   can %s read  BIOS\n",  fmba.ME_BIOS_read     ? "   " : "NOT");
+	msg_pdbg("ME   can %s read  descr\n", fmba.ME_descr_read    ? "   " : "NOT");
+	msg_pdbg("GbE  can %s write GbE\n",   fmba.GbE_GbE_write    ? "   " : "NOT");
+	msg_pdbg("GbE  can %s write ME\n",    fmba.GbE_ME_write     ? "   " : "NOT");
+	msg_pdbg("GbE  can %s write BIOS\n",  fmba.GbE_BIOS_write   ? "   " : "NOT");
+	msg_pdbg("GbE  can %s write descr\n", fmba.GbE_descr_write  ? "   " : "NOT");
+	msg_pdbg("GbE  can %s read  GbE\n",   fmba.GbE_GbE_read     ? "   " : "NOT");
+	msg_pdbg("GbE  can %s read  ME\n",    fmba.GbE_ME_read      ? "   " : "NOT");
+	msg_pdbg("GbE  can %s read  BIOS\n",  fmba.GbE_BIOS_read    ? "   " : "NOT");
+	msg_pdbg("GbE  can %s read  descr\n", fmba.GbE_descr_read   ? "   " : "NOT");
+}
+
+void prettyprint_ich9_reg_vscc(uint32_t reg_val)
+{
+	pprint_reg_hex(VSCC, BES, reg_val, ", ");
+	pprint_reg(VSCC, WG, reg_val, ", ");
+	pprint_reg(VSCC, WSR, reg_val, ", ");
+	pprint_reg(VSCC, WEWS, reg_val, ", ");
+	pprint_reg_hex(VSCC, EO, reg_val, ", ");
+	pprint_reg(VSCC, VCL, reg_val, "\n");
+}
+
+
+#ifdef ICH_DESCRIPTORS_FROM_MMAP_DUMP
+void prettyprint_ich_descriptor_straps_ich8(void)
+{
+	const char * const str_GPIO12[4] = {
+		"GPIO12",
+		"LAN PHY Power Control Function (Native Output)",
+		"GLAN_DOCK# (Native Input)",
+		"invalid configuration",
+	};
+
+	msg_pdbg("\n");
+	msg_pdbg("=== FISBA ===\n");
+	msg_pdbg("STRP0    0x%8.8x\n", fisba.ich8.STRP0);
+
+	msg_pdbg("\n");
+	msg_pdbg("--- FISBA details ---\n");
+	msg_pdbg("ME SMBus addr2 0x%2.2x\n", fisba.ich8.ASD2);
+	msg_pdbg("ME SMBus addr1 0x%2.2x\n", fisba.ich8.ASD);
+	msg_pdbg("ME SMBus Controller is connected to %s\n", fisba.ich8.MESM2SEL ? "SMLink pins" : "SMBus pins");
+	msg_pdbg("SPI CS1 is used for %s\n", fisba.ich8.SPICS1_LANPHYPC_SEL ? "LAN PHY Power Control Function" : "SPI Chip Select");
+	msg_pdbg("GPIO12_SEL is used as %s\n", str_GPIO12[fisba.ich8.GPIO12_SEL]);
+	msg_pdbg("PCIe Port 6 is used for %s\n", fisba.ich8.GLAN_PCIE_SEL ? "integrated GLAN" : "PCI Express");
+	msg_pdbg("Intel AMT SMBus Controller 1 is connected to %s\n",   fisba.ich8.BMCMODE ? "SMLink" : "SMBus");
+	msg_pdbg("TCO slave is on %s. Intel AMT SMBus Controller 1 is %sabled\n",
+		fisba.ich8.TCOMODE ? "SMBus" : "SMLink", fisba.ich8.TCOMODE ? "en" : "dis");
+	msg_pdbg("ME A is %sabled\n", fisba.ich8.ME_DISABLE ? "dis" : "en");
+
+	msg_pdbg("\n");
+	msg_pdbg("=== FMSBA ===\n");
+	msg_pdbg("STRP1    0x%8.8x\n", fisba.ich8.STRP1);
+
+	msg_pdbg("\n");
+	msg_pdbg("--- FMSBA details ---\n");
+	msg_pdbg("ME B is %sabled\n", fisba.ich8.ME_disable_B ? "dis" : "en");
+}
+
+void prettyprint_ich_descriptor_straps_ibex(void)
+{
+	int i;
+	msg_pdbg("\n");
+	msg_pdbg("=== FPSBA ===\n");
+	for(i = 0; i <= 15; i++)
+		msg_pdbg("STRP%-2d = 0x%8.8x\n", i, fisba.ibex.STRPs[i]);
+}
+
+void prettyprint_ich_descriptor_straps(enum chipset cs)
+{
+	switch (cs) {
+	case CHIPSET_ICH8:
+		prettyprint_ich_descriptor_straps_ich8();
+		break;
+	case CHIPSET_SERIES_5_IBEX_PEAK:
+		prettyprint_ich_descriptor_straps_ibex();
+		break;
+	default:
+		break;
+	}
+}
+
+void prettyprint_rdid(uint32_t reg_val)
+{
+	uint8_t mid = reg_val & 0xFF;
+	uint16_t did = ((reg_val >> 16) & 0xFF) | (reg_val & 0xFF00);
+	msg_pdbg("Manufacturer ID 0x%02x, Device ID 0x%04x\n", mid, did);
+}
+
+void prettyprint_ich_descriptor_upper_map(void)
+{
+	int i;
+	msg_pdbg("\n");
+	msg_pdbg("=== FLUMAP ===\n");
+	msg_pdbg("FLUMAP1  0x%8.8x\n", flumap.FLUMAP1);
+
+	msg_pdbg("\n");
+	msg_pdbg("--- FLUMAP details ---\n");
+	msg_pdbg("VTL  (length)       = %d\n", flumap.VTL);
+	msg_pdbg("VTBA (base address) = 0x%6.6x\n", desc_addr.VTBA());
+	msg_pdbg("\n");
+
+	for (i=0; i < flumap.VTL/2; i++)
+	{
+		uint32_t jid = flumap.vscc_table[i].JID;
+		uint32_t vscc = flumap.vscc_table[i].VSCC;
+		msg_pdbg("  JID%d  = 0x%8.8x\n", i, jid);
+		msg_pdbg("  VSCC%d = 0x%8.8x\n", i, vscc);
+		msg_pdbg("    "); /* indention */
+		prettyprint_rdid(jid);
+		msg_pdbg("    "); /* indention */
+		prettyprint_ich9_reg_vscc(vscc);
+	}
+}
+
+int read_ich_descriptors_from_dump(uint32_t *dump)
+{
+	int i;
+	uint8_t pch_bug_offset = 0;
+	if (dump[0] != DESCRIPTOR_MODE_MAGIC) {
+		if (dump[4] == DESCRIPTOR_MODE_MAGIC)
+			pch_bug_offset = 4;
+		else
+			return -1;
+	}
+
+	/* map */
+	fdbar.FLVALSIG	= dump[0 + pch_bug_offset];
+	fdbar.FLMAP0	= dump[1 + pch_bug_offset];
+	fdbar.FLMAP1	= dump[2 + pch_bug_offset];
+	fdbar.FLMAP2	= dump[3 + pch_bug_offset];
+
+	/* component */
+	fcba.FLCOMP	= dump[(desc_addr.FCBA() >> 2) + 0];
+	fcba.FLILL	= dump[(desc_addr.FCBA() >> 2) + 1];
+	fcba.FLPB	= dump[(desc_addr.FCBA() >> 2) + 2];
+
+	/* region */
+	frba.FLREG0 = dump[(desc_addr.FRBA() >> 2) + 0];
+	frba.FLREG1 = dump[(desc_addr.FRBA() >> 2) + 1];
+	frba.FLREG2 = dump[(desc_addr.FRBA() >> 2) + 2];
+	frba.FLREG3 = dump[(desc_addr.FRBA() >> 2) + 3];
+
+	/* master */
+	fmba.FLMSTR1 = dump[(desc_addr.FMBA() >> 2) + 0];
+	fmba.FLMSTR2 = dump[(desc_addr.FMBA() >> 2) + 1];
+	fmba.FLMSTR3 = dump[(desc_addr.FMBA() >> 2) + 2];
+
+	/* upper map */
+	flumap.FLUMAP1 = dump[(0x0efc >> 2) + 0];
+
+	for (i=0; i < flumap.VTL; i++)
+	{
+		flumap.vscc_table[i].JID  = dump[(desc_addr.VTBA() >> 2) + i * 2 + 0];
+		flumap.vscc_table[i].VSCC = dump[(desc_addr.VTBA() >> 2) + i * 2 + 1];
+	}
+	/* straps */
+	/* FIXME: detect chipset correctly */
+	switch (CHIPSET_SERIES_5_IBEX_PEAK) {
+		case CHIPSET_ICH8:
+			fisba.ich8.STRP0 = dump[(desc_addr.FISBA() >> 2) + 0];
+			fisba.ich8.STRP1 = dump[(desc_addr.FMSBA() >> 2) + 0];
+			break;
+		case CHIPSET_SERIES_5_IBEX_PEAK:
+			for(i = 0; i <= 15; i++)
+				fisba.ibex.STRPs[i] = dump[(desc_addr.FISBA() >> 2) + i];
+			break;
+		default:
+			break;
+	}
+
+	return 0;
+}
+#else // ICH_DESCRIPTORS_FROM_MMAP_DUMP
+
+static uint32_t read_descriptor_reg(uint8_t section, uint16_t offset, void *spibar)
+{
+	uint32_t control = 0;
+	control |= (section << FDOC_FDSS_OFF) & FDOC_FDSS;
+	control |= (offset << FDOC_FDSI_OFF) & FDOC_FDSI;
+	*(volatile uint32_t *) (spibar + ICH9_REG_FDOC) = control;
+	return *(volatile uint32_t *)(spibar + ICH9_REG_FDOD);
+}
+
+void read_ich_descriptors_from_fdo(void *spibar)
+{
+	msg_pdbg("Reading flash descriptors "
+		 "mapped by the chipset via FDOC/FDOD...");
+	/* descriptor map section */
+	fdbar.FLVALSIG	= read_descriptor_reg(0, 0, spibar);
+	fdbar.FLMAP0	= read_descriptor_reg(0, 1, spibar);
+	fdbar.FLMAP1	= read_descriptor_reg(0, 2, spibar);
+	fdbar.FLMAP2	= read_descriptor_reg(0, 3, spibar);
+
+	/* component section */
+	fcba.FLCOMP	= read_descriptor_reg(1, 0, spibar);
+	fcba.FLILL	= read_descriptor_reg(1, 1, spibar);
+	fcba.FLPB	= read_descriptor_reg(1, 2, spibar);
+
+	/* region section */
+	frba.FLREG0 = read_descriptor_reg(2, 0, spibar);
+	frba.FLREG1 = read_descriptor_reg(2, 1, spibar);
+	frba.FLREG2 = read_descriptor_reg(2, 2, spibar);
+	frba.FLREG3 = read_descriptor_reg(2, 3, spibar);
+
+	/* master section */
+	fmba.FLMSTR1 = read_descriptor_reg(3, 0, spibar);
+	fmba.FLMSTR2 = read_descriptor_reg(3, 1, spibar);
+	fmba.FLMSTR3 = read_descriptor_reg(3, 2, spibar);
+
+	/* strap section and upper map */
+	/* impossible via FDOC/FDOD(?) */
+	msg_pdbg(" done\n");
+}
+
+#endif // ICH_DESCRIPTORS_FROM_MMAP_DUMP
+#endif // defined(__i386__) || defined(__x86_64__)
diff --git a/ich_descriptors.h b/ich_descriptors.h
new file mode 100644
index 0000000..627852d
--- /dev/null
+++ b/ich_descriptors.h
@@ -0,0 +1,447 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (c) 2010  Matthias Wenzel <bios at mazzoo dot de>
+ * Copyright (c) 2011  Stefan Tauner
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdint.h>
+
+#if defined(__i386__) || defined(__x86_64__)
+#ifndef __ICH_DESCRIPTORS_H__
+#define __ICH_DESCRIPTORS_H__ 1
+
+/* should probably be in ichspi.h */
+#define msg_pdbg2 msg_pspew
+
+#define ICH9_REG_FDOC		0xB0	/* 32 Bits Flash Descriptor Observability Control */
+					/* 0-1: reserved */
+#define FDOC_FDSI_OFF		2	/* 2-11: Flash Descriptor Section Index */
+#define FDOC_FDSI		(0x3f << FDOC_FDSI_OFF)
+#define FDOC_FDSS_OFF		12	/* 12-14: Flash Descriptor Section Select */
+#define FDOC_FDSS		(0x3 << FDOC_FDSS_OFF)
+					/* 15-31: reserved */
+
+#define ICH9_REG_FDOD		0xB4	/* 32 Bits Flash Descriptor Observability Data */
+
+/* Field locations and semantics for LVSCC, UVSCC and related words in the flash
+ * descriptor are equal therefore they all share the same macros below. */
+#define VSCC_BES_OFF		0	/* 0-1: Block/Sector Erase Size */
+#define VSCC_BES			(0x3 << VSCC_BES_OFF)
+#define VSCC_WG_OFF		2	/* 2: Write Granularity */
+#define VSCC_WG				(0x1 << VSCC_WG_OFF)
+#define VSCC_WSR_OFF		3	/* 3: Write Status Required */
+#define VSCC_WSR			(0x1 << VSCC_WSR_OFF)
+#define VSCC_WEWS_OFF		4	/* 4: Write Enable on Write Status */
+#define VSCC_WEWS			(0x1 << VSCC_WEWS_OFF)
+					/* 5-7: reserved */
+#define VSCC_EO_OFF		8	/* 8-15: Erase Opcode */
+#define VSCC_EO				(0xff << VSCC_EO_OFF)
+					/* 16-22: reserved */
+#define VSCC_VCL_OFF		23	/* 23: Vendor Component Lock */
+#define VSCC_VCL			(0x1 << VSCC_VCL_OFF)
+					/* 24-31: reserved */
+
+#define pprint_reg(reg, bit, val, sep) msg_pdbg("%s=%d" sep, #bit, (val & reg##_##bit)>>reg##_##bit##_OFF)
+#define pprint_reg_hex(reg, bit, val, sep) msg_pdbg("%s=0x%x" sep, #bit, (val & reg##_##bit)>>reg##_##bit##_OFF)
+void prettyprint_ich9_reg_vscc(uint32_t reg_val);
+
+enum chipset {
+	CHIPSET_ICH8,
+	CHIPSET_ICH9,
+	CHIPSET_ICH10,
+	CHIPSET_SERIES_5_IBEX_PEAK,
+	CHIPSET_SERIES_6_COUGAR_POINT,
+	CHIPSET_SERIES_7_PANTHER_POINT
+};
+
+struct flash_descriptor_addresses {
+	uint32_t (*FCBA)(void);
+	uint32_t (*FRBA)(void);
+	uint32_t (*FMBA)(void);
+	uint32_t (*FMSBA)(void);
+	uint32_t (*FLREG_limit)(uint32_t flreg);
+	uint32_t (*FLREG_base)(uint32_t flreg);
+	uint32_t (*FISBA)(void);
+#ifdef ICH_DESCRIPTORS_FROM_MMAP_DUMP
+	uint32_t (*VTBA)(void);
+#endif // ICH_DESCRIPTORS_FROM_MMAP_DUMP
+};
+	
+struct flash_descriptor {
+	uint32_t FLVALSIG;	/* 0x00 */
+	union {			/* 0x04 */
+		uint32_t FLMAP0;
+		struct {
+			uint8_t FCBA	:8;
+			uint8_t NC	:2;
+			unsigned	:6;
+			uint8_t FRBA	:8;
+			uint8_t NR	:3;
+			unsigned	:5;
+		};
+	};
+	union {			/* 0x08 */
+		uint32_t FLMAP1;
+		struct {
+			uint8_t FMBA	:8;
+			uint8_t NM	:3;
+			unsigned	:5;
+			union {
+				uint8_t FISBA	:8;
+				uint8_t FPSBA	:8;
+			};
+			uint8_t ISL	:8;
+		};
+	};
+	union {			/* 0x0c */
+		uint32_t FLMAP2;
+		struct {
+			uint8_t  FMSBA	:8;
+			uint8_t  MSL	:8;
+			unsigned	:16;
+		};
+	};
+};
+
+struct flash_component {
+	union {			/* 0x00 */
+		uint32_t FLCOMP;
+		struct {
+			uint8_t  comp1_density	:3;
+			uint8_t  comp2_density	:3;
+			unsigned		:11;
+			uint8_t  freq_read	:3;
+			uint8_t  fastread	:1;
+			uint8_t  freq_fastread	:3;
+			uint8_t  freq_write	:3;
+			uint8_t  freq_read_id	:3;
+			unsigned		:2;
+		};
+	};
+	union {			/* 0x04 */
+		uint32_t FLILL;
+		struct {
+			uint8_t invalid_instr0;
+			uint8_t invalid_instr1;
+			uint8_t invalid_instr2;
+			uint8_t invalid_instr3;
+		};
+	};
+	union {			/* 0x08 */
+		uint32_t FLPB;
+		struct {
+			uint16_t FPBA	:13;
+			unsigned	:19;
+		};
+	};
+};
+
+struct flash_region {
+	
+	union {
+		uint32_t FLREG0; /* Flash Descriptor */
+		struct {
+			uint16_t reg0_base	:13;
+			unsigned		:3;
+			uint16_t reg0_limit	:13;
+			unsigned		:3;
+		};
+	};
+	union {
+		uint32_t FLREG1; /* BIOS */
+		struct {
+			uint16_t reg1_base	:13;
+			unsigned		:3;
+			uint16_t reg1_limit	:13;
+			unsigned		:3;
+		};
+	};
+	union {
+		uint32_t FLREG2; /* ME */
+		struct {
+			uint16_t reg2_base	:13;
+			unsigned		:3;
+			uint16_t reg2_limit	:13;
+			unsigned		:3;
+		};
+	};
+	union {
+		uint32_t FLREG3; /* GbE */
+		struct {
+			uint16_t reg3_base	:13;
+			unsigned		:3;
+			uint16_t reg3_limit	:13;
+			unsigned		:3;
+		};
+	};
+} frba;
+
+struct flash_master {
+	union {
+		uint32_t FLMSTR1;
+		struct {
+			uint16_t BIOS_req_ID		:16;
+			uint8_t  BIOS_descr_read	:1;
+			uint8_t  BIOS_BIOS_read		:1;
+			uint8_t  BIOS_ME_read		:1;
+			uint8_t  BIOS_GbE_read		:1;
+			uint8_t  BIOS_plat_read		:1;
+			unsigned			:3;
+			uint8_t  BIOS_descr_write	:1;
+			uint8_t  BIOS_BIOS_write	:1;
+			uint8_t  BIOS_ME_write		:1;
+			uint8_t  BIOS_GbE_write		:1;
+			uint8_t  BIOS_plat_write	:1;
+			unsigned			:3;
+		};
+	};
+	union {
+		uint32_t FLMSTR2;
+		struct {
+			uint16_t ME_req_ID		:16;
+			uint8_t  ME_descr_read	:1;
+			uint8_t  ME_BIOS_read		:1;
+			uint8_t  ME_ME_read		:1;
+			uint8_t  ME_GbE_read		:1;
+			uint8_t  ME_plat_read		:1;
+			unsigned			:3;
+			uint8_t  ME_descr_write		:1;
+			uint8_t  ME_BIOS_write		:1;
+			uint8_t  ME_ME_write		:1;
+			uint8_t  ME_GbE_write		:1;
+			uint8_t  ME_plat_write		:1;
+			unsigned			:3;
+		};
+	};
+	union {
+		uint32_t FLMSTR3;
+		struct {
+			uint16_t GbE_req_ID		:16;
+			uint8_t  GbE_descr_read		:1;
+			uint8_t  GbE_BIOS_read		:1;
+			uint8_t  GbE_ME_read		:1;
+			uint8_t  GbE_GbE_read		:1;
+			uint8_t  GbE_plat_read		:1;
+			unsigned			:3;
+			uint8_t  GbE_descr_write	:1;
+			uint8_t  GbE_BIOS_write		:1;
+			uint8_t  GbE_ME_write		:1;
+			uint8_t  GbE_GbE_write		:1;
+			uint8_t  GbE_plat_write		:1;
+			unsigned			:3;
+		};
+	};
+};
+
+#ifdef ICH_DESCRIPTORS_FROM_MMAP_DUMP
+struct flash_strap {
+	union {
+		struct {
+			union {
+				uint32_t STRP0;
+				struct {
+					uint8_t  ME_DISABLE		:1;
+					unsigned			:6;
+					uint8_t  TCOMODE		:1;
+					uint8_t  ASD			:7;
+					uint8_t  BMCMODE		:1;
+					unsigned			:3;
+					uint8_t  GLAN_PCIE_SEL		:1;
+					uint8_t  GPIO12_SEL		:2;
+					uint8_t  SPICS1_LANPHYPC_SEL	:1;
+					uint8_t  MESM2SEL		:1;
+					unsigned			:1;
+					uint8_t  ASD2			:7;
+				};
+			};
+			union {
+				uint32_t STRP1;
+				struct {
+					uint8_t  ME_disable_B		:1;
+					unsigned			:31;
+				};
+			};
+		}ich8;
+		union {
+			uint32_t STRPs[15];
+			struct {
+				union {
+					uint32_t STRP0;
+					struct {
+						unsigned			:1;
+						uint8_t  cs_ss2			:1;
+						unsigned			:5;
+						uint8_t  SMB_EN			:1;
+						uint8_t  SML0_EN		:1;
+						uint8_t  SML1_EN		:1;
+						uint8_t  SML1FRQ		:2;
+						uint8_t  SMB0FRQ		:2;
+						uint8_t  SML0FRQ		:2;
+						unsigned			:4;
+						uint8_t  LANPHYPC_GP12_SEL	:1;
+						uint8_t  cs_ss1			:1;
+						unsigned			:2;
+						uint8_t  DMI_REQID_DIS		:1;
+						unsigned			:4;
+						uint8_t  BBBS			:2;
+						unsigned			:1;
+					};
+				};
+				union {
+					uint32_t STRP1;
+					struct {
+					};
+				};
+				union {
+					uint32_t STRP2;
+					struct {
+					};
+				};
+				union {
+					uint32_t STRP3;
+					struct {
+					};
+				};
+				union {
+					uint32_t STRP4;
+					struct {
+					};
+				};
+				union {
+					uint32_t STRP5;
+					struct {
+					};
+				};
+				union {
+					uint32_t STRP6;
+					struct {
+					};
+				};
+				union {
+					uint32_t STRP7;
+					struct {
+					};
+				};
+				union {
+					uint32_t STRP8;
+					struct {
+					};
+				};
+				union {
+					uint32_t STRP9;
+					struct {
+					};
+				};
+				union {
+					uint32_t STRP10;
+					struct {
+					};
+				};
+				union {
+					uint32_t STRP11;
+					struct {
+					};
+				};
+				union {
+					uint32_t STRP12;
+					struct {
+					};
+				};
+				union {
+					uint32_t STRP13;
+					struct {
+					};
+				};
+				union {
+					uint32_t STRP14;
+					struct {
+					};
+				};
+				union {
+					uint32_t STRP15;
+					struct {
+					};
+				};
+			};
+		}ibex;
+	};
+};
+
+struct flash_upper_map {
+	union {
+		uint32_t FLUMAP1;
+		struct {
+			uint8_t  VTBA	:8;
+			uint8_t  VTL	:8;
+			unsigned	:16;
+		};
+	};
+	struct {
+		union {
+			uint32_t JID;
+			struct {
+				uint8_t vid	:8;
+				uint8_t cid0	:8;
+				uint8_t cid1	:8;
+				unsigned	:8;
+			};
+		};
+		union {
+			uint32_t VSCC;
+			struct {
+				uint8_t  ubes	:2;
+				uint8_t  uwg	:1;
+				uint8_t  uwsr	:1;
+				uint8_t  uwews	:1;
+				unsigned	:3;
+				uint8_t  ueo	:8;
+				uint8_t  lbes	:2;
+				uint8_t  lwg	:1;
+				uint8_t  lwsr	:1;
+				uint8_t  lwews	:1;
+				unsigned	:3;
+				uint16_t leo	:16;
+			};
+		};
+	}vscc_table[128];
+};
+#endif // ICH_DESCRIPTORS_FROM_MMAP_DUMP
+
+void prettyprint_ich_descriptors(void);
+
+void prettyprint_ich_descriptor_map(void);
+void prettyprint_ich_descriptor_component(void);
+void prettyprint_ich_descriptor_region(void);
+void prettyprint_ich_descriptor_master(void);
+
+int getFCBA_component_density(uint8_t comp);
+
+#ifdef ICH_DESCRIPTORS_FROM_MMAP_DUMP
+
+void prettyprint_ich_descriptor_upper_map(void);
+void prettyprint_ich_descriptor_straps(enum chipset cs);
+int read_ich_descriptors_from_dump(uint32_t *dump);
+
+#else // ICH_DESCRIPTORS_FROM_MMAP_DUMP
+
+void read_ich_descriptors_from_fdo(void *spibar);
+
+#endif // ICH_DESCRIPTORS_FROM_MMAP_DUMP
+
+#endif // __ICH_DESCRIPTORS_H__
+#endif // defined(__i386__) || defined(__x86_64__)
diff --git a/ichspi.c b/ichspi.c
index f41cb76..07793b0 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -6,6 +6,7 @@
  * Copyright (C) 2008 Dominik Geyer <dominik.geyer at kontron.com>
  * Copyright (C) 2008 coresystems GmbH <info at coresystems.de>
  * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
+ * Copyright (C) 2011 Stefan Tauner
  *
  * 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
@@ -41,6 +42,7 @@
 #include "chipdrivers.h"
 #include "programmer.h"
 #include "spi.h"
+#include "ich_descriptors.h"
 
 /* ICH9 controller register definition */
 #define ICH9_REG_HSFS		0x04	/* 16 Bits Hardware Sequencing Flash Status */
@@ -131,6 +133,14 @@
 #define ICH9_REG_BBAR		0xA0	/* 32 Bits BIOS Base Address Configuration */
 #define BBAR_MASK	0x00ffff00		/* 8-23: Bottom of System Flash */
 
+#define ICH9_REG_LVSCC		0xC4	/* 32 Bits Host Lower Vendor Specific Component Capabilities */
+#define ICH9_REG_UVSCC		0xC8	/* 32 Bits Host Upper Vendor Specific Component Capabilities */
+/* The individual fields of the VSCC registers are defined in the file
+ * ich_descriptors.h. The reason is that the same fields are also used in the
+ * flash descriptors to define the properties of the different flash chips
+ * supported by the BIOS image. These descriptors are also the source for the
+ * registers above. */
+
 #define ICH9_REG_FPB		0xD0	/* 32 Bits Flash Partition Boundary */
 #define FPB_FPBA_OFF		0	/* 0-12: Block/Sector Erase Size */
 #define FPB_FPBA			(0x1FFF << FPB_FPBA_OFF)
@@ -293,7 +303,7 @@ static OPCODE POSSIBLE_OPCODES[] = {
 static OPCODES O_EXISTING = {};
 
 /* pretty printing functions */
-static void pretty_print_opcodes(OPCODES *ops)
+static void prettyprint_opcodes(OPCODES *ops)
 {
 	if(ops == NULL)
 		return;
@@ -313,8 +323,6 @@ static void pretty_print_opcodes(OPCODES *ops)
 	}
 }
 
-#define pprint_reg(reg, bit, val, sep) msg_pdbg("%s=%d" sep, #bit, (val & reg##_##bit)>>reg##_##bit##_OFF)
-
 static void prettyprint_ich9_reg_hsfs(uint16_t reg_val)
 {
 	msg_pdbg("HSFS: ");
@@ -627,7 +635,7 @@ static int ich_init_opcodes(void)
 	} else {
 		curopcodes = curopcodes_done;
 		msg_pdbg("done\n");
-		pretty_print_opcodes(curopcodes);
+		prettyprint_opcodes(curopcodes);
 		msg_pdbg("\n");
 		return 0;
 	}
@@ -1209,6 +1217,7 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
 	uint8_t old, new;
 	uint16_t spibar_offset, tmp2;
 	uint32_t tmp;
+	int ichspi_desc = 0;
 
 	switch (ich_generation) {
 	case 7:
@@ -1280,6 +1289,8 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
 			msg_pinfo("WARNING: SPI Configuration Lockdown activated.\n");
 			ichspi_lock = 1;
 		}
+		if (tmp2 & HSFS_FDV)
+			ichspi_desc = 1;
 
 		tmp2 = mmio_readw(ich_spibar + ICH9_REG_HSFC);
 		msg_pdbg("0x06: 0x%04x (HSFC)\n", tmp2);
@@ -1328,9 +1339,25 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
 		ichspi_bbar = mmio_readl(ich_spibar + ICH9_REG_BBAR);
 		msg_pdbg("0xA0: 0x%08x (BBAR)\n",
 			     ichspi_bbar);
+
+		tmp = mmio_readl(ich_spibar + ICH9_REG_LVSCC);
+		msg_pdbg("0xC4: 0x%08x (LVSCC)\n", tmp);
+		msg_pdbg("LVSCC: ");
+		prettyprint_ich9_reg_vscc(tmp);
+
+		tmp = mmio_readl(ich_spibar + ICH9_REG_UVSCC);
+		msg_pdbg("0xC8: 0x%08x (UVSCC)\n", tmp);
+		msg_pdbg("UVSCC: ");
+		prettyprint_ich9_reg_vscc(tmp);
+
 		tmp = mmio_readl(ich_spibar + ICH9_REG_FPB);
 		msg_pdbg("0xD0: 0x%08x (FPB)\n", tmp);
 
+		msg_pdbg("\n");
+		if (ichspi_desc) {
+			read_ich_descriptors_from_fdo(ich_spibar);
+			prettyprint_ich_descriptors();
+		}
 		ich_init_opcodes();
 		break;
 	default:
diff --git a/util/ich_descriptors_tool/Makefile b/util/ich_descriptors_tool/Makefile
new file mode 100644
index 0000000..0592b67
--- /dev/null
+++ b/util/ich_descriptors_tool/Makefile
@@ -0,0 +1,42 @@
+CC ?= gcc
+
+PROGRAM=ich_descriptors_tool
+EXTRAINCDIRS = ../../ .
+DEPPATH = .dep
+OBJATH = .obj
+SHAREDSRC = ich_descriptors.c
+SHAREDSRCDIR = ../..
+
+SRC = $(wildcard *.c)
+
+CFLAGS=-Wall
+CFLAGS += -MMD -MP -MF $(DEPPATH)/$(@F).d
+# enables functions that populate the descriptor structs from plain dump arrays
+CFLAGS += -D ICH_DESCRIPTORS_FROM_MMAP_DUMP
+CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
+
+OBJ = $(OBJATH)/$(SRC:%.c=%.o)
+
+SHAREDOBJ = $(OBJATH)/$(notdir $(SHAREDSRC:%.c=%.o))
+
+all:$(PROGRAM)
+
+$(OBJ): $(OBJATH)/%.o : %.c
+	$(CC) $(CFLAGS) -o $@ -c $<
+
+# this enables us to NOT share object files with flashrom,
+# which would lead to unexpected results otherwise (w/o running make clean)
+$(SHAREDOBJ): $(OBJATH)/%.o : $(SHAREDSRCDIR)/%.c
+	$(CC) $(CFLAGS) -o $@ -c $<
+
+$(PROGRAM): $(OBJ) $(SHAREDOBJ)
+	$(CC) -o $(PROGRAM) $(OBJ) $(SHAREDOBJ)
+
+clean:
+	rm -f $(PROGRAM)
+	rm -rf $(DEPPATH) $(OBJATH)
+
+# Include the dependency files.
+-include $(shell mkdir -p $(DEPPATH) $(OBJATH) 2>/dev/null) $(wildcard $(DEPPATH)/*)
+
+.PHONY: all clean
diff --git a/util/ich_descriptors_tool/TODO b/util/ich_descriptors_tool/TODO
new file mode 100644
index 0000000..e3933ee
--- /dev/null
+++ b/util/ich_descriptors_tool/TODO
@@ -0,0 +1,5 @@
+- reverse the path, as in assemble a descriptormode image from various
+  blobs (BIOS, GbE, ME, OEM) and a description (xml? custom config?
+  sane defaults and cmd-line switches?)
+- dump 256 OEM bytes
+- handle descriptors of various chipsets correctly
\ No newline at end of file
diff --git a/util/ich_descriptors_tool/ich_descriptors_tool.c b/util/ich_descriptors_tool/ich_descriptors_tool.c
new file mode 100644
index 0000000..6c6aa03
--- /dev/null
+++ b/util/ich_descriptors_tool/ich_descriptors_tool.c
@@ -0,0 +1,226 @@
+/*
+ * dump information and binaries from BIOS images that are in descriptor mode/soft-strap
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * authors:
+ * (c) 2010  Matthias Wenzel <bios at mazzoo dot de>
+ * (c) 2011  Stefan Tauner
+ *
+ * */
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "flash.h"
+#include "ich_descriptors.h"
+
+extern struct flash_descriptor fdbar;
+extern struct flash_component fcba;
+extern struct flash_region frba;
+extern struct flash_master fmba;
+extern struct flash_strap fisba;
+extern struct flash_upper_map flumap;
+extern struct flash_descriptor_addresses desc_addr;
+
+static int f;         /* file descriptor to flash file */
+static int fs;        /* file size */
+static uint32_t *fm; /* mmap'd file */
+
+void dump_file_descriptor(char * fn)
+{
+	char * n = malloc(strlen(fn) + 11);
+	snprintf(n, strlen(fn) + 11, "%s.descr.bin", fn);
+	printf("\n");
+	printf("+++ dumping %s ... ", n);
+	int fh = open(n, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+	free(n);
+	if (fh < 0)
+	{
+		printf("ERROR: couldn't open(%s): %s\n", n, strerror(errno));
+		exit(1);
+	}
+
+	int ret;
+	ret = write(fh, &fm[frba.reg0_base >> 2], frba.reg0_limit);
+	if (ret != frba.reg0_limit)
+	{
+		printf("FAILED.\n");
+		exit(1);
+	}
+
+	printf("done.\n");
+
+	close(fh);
+}
+
+void dump_file_BIOS(char * fn)
+{
+	char * n = malloc(strlen(fn) + 10);
+	snprintf(n, strlen(fn) + 10, "%s.BIOS.bin", fn);
+	printf("\n");
+	printf("+++ dumping %s ... ", n);
+	int fh = open(n, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+	free(n);
+	if (fh < 0)
+	{
+		printf("ERROR: couldn't open(%s): %s\n", n, strerror(errno));
+		exit(1);
+	}
+
+	int ret;
+	ret = write(fh, &fm[frba.reg1_base >> 2], frba.reg1_limit);
+	if (ret != frba.reg1_limit)
+	{
+		printf("FAILED.\n");
+		exit(1);
+	}
+
+	printf("done.\n");
+
+	close(fh);
+}
+
+void dump_file_ME(char * fn)
+{
+	char * n = malloc(strlen(fn) + 8);
+	snprintf(n, strlen(fn) + 8, "%s.ME.bin", fn);
+	printf("\n");
+	printf("+++ dumping %s ... ", n);
+	int fh = open(n, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+	free(n);
+	if (fh < 0)
+	{
+		printf("ERROR: couldn't open(%s): %s\n", n, strerror(errno));
+		exit(1);
+	}
+
+	int ret;
+	ret = write(fh, &fm[frba.reg2_base >> 2], frba.reg2_limit);
+	if (ret != frba.reg2_limit)
+	{
+		printf("FAILED.\n");
+		exit(1);
+	}
+
+	printf("done.\n");
+
+	close(fh);
+}
+
+void dump_file_GbE(char * fn)
+{
+	char * n = malloc(strlen(fn) + 9);
+	snprintf(n, strlen(fn) + 9, "%s.GbE.bin", fn);
+	printf("\n");
+	printf("+++ dumping %s ... ", n);
+	int fh = open(n, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+	free(n);
+	if (fh < 0)
+	{
+		printf("ERROR: couldn't open(%s): %s\n", n, strerror(errno));
+		exit(1);
+	}
+
+	int ret;
+	ret = write(fh, &fm[frba.reg3_base >> 2], frba.reg3_limit);
+	if (ret != frba.reg3_limit)
+	{
+		printf("FAILED.\n");
+		exit(1);
+	}
+
+	printf("done.\n");
+	uint8_t * pMAC = (uint8_t *) &fm[frba.reg3_base >> 2];
+	printf("the MAC-address might be: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
+		pMAC[0],
+		pMAC[1],
+		pMAC[2],
+		pMAC[3],
+		pMAC[4],
+		pMAC[5]
+		);
+
+	close(fh);
+}
+
+void dump_files(char * n)
+{
+	printf("=== dumping section files ===\n");
+	if (frba.reg0_limit)
+		dump_file_descriptor(n);
+	if (frba.reg1_limit)
+		dump_file_BIOS(n);
+	if (frba.reg2_limit)
+		dump_file_ME(n);
+	if (frba.reg3_limit)
+		dump_file_GbE(n);
+}
+
+void usage(char ** argv, char* error)
+{
+	printf("%s\n", error);
+	printf("\n");
+	printf("usage: '%s <bios image file> [-d]'\n", argv[0]);
+	printf("\n");
+	printf("\twhere <bios image file> isn't actually a BIOS image, but the SPI flash\n");
+	printf("\tcontents of the SPI connected to your intel chipset.\n");
+	printf("\tIn case that image is really in descriptor mode (a.k.a soft-strap)\n");
+	printf("\t%s will pretty print all relevant information.\n", argv[0]);
+	printf("\tIf '-d' is specified as the second parameter some sections such as\n");
+	printf("\tthe real BIOS image as seen by the CPU or a GbE blob that is\n");
+	printf("\trequired to initialize your ICH GbE are also dumped to files.\n");
+	exit(1);
+}
+
+int main(int argc, char **argv)
+{
+	if (argc < 2)
+		usage(argv, "Need at least one parameter");
+	f = open(argv[1], O_RDONLY);
+	if (f < 0)
+		usage(argv, "No such file");
+	if (argc >= 3 && (strcmp("-d", argv[2]) == 0))
+		usage(argv, "Bogus second argument");
+
+	fs = lseek(f, 0, SEEK_END);
+	if (fs < 0)
+		usage(argv, "Seeking to the end of the file failed");
+
+	fm = mmap(NULL, fs, PROT_READ, MAP_PRIVATE, f, 0);
+	if (fm == (void *) -1)
+	{
+		/* fallback for stupid OSes like cygwin */
+		int ret;
+		fm = malloc(fs);
+		if (!fm)
+			usage(argv, "Could not allocate memory");
+		lseek(f, 0, SEEK_SET);
+		ret = read(f, fm, fs);
+		if (ret != fs)
+			usage(argv, "Seeking to the end of the file failed");
+	}
+	printf("flash image is %d [0x%x] bytes\n", fs, fs);
+	close(f);
+
+	if(read_ich_descriptors_from_dump(fm)){
+		printf("not in descriptor mode\n");
+		exit(1);
+	}
+
+	prettyprint_ich_descriptors();
+
+	if (argc >= 3)
+		dump_files(argv[1]);
+
+	return 0;
+}
+
-- 
1.7.1





More information about the flashrom mailing list