additionally to what is available via FDOC/FDOD this allows to access: - the softstraps which are used to configure the chipset by flash content without the need for BIOS routines. on ICH8 it is possible to read those with FDOC/FDOC too, but this was removed in later chipsets. - the ME VSCC (Vendor Specific Component Capabilities) table. simply put, this is an SPI chip database used to figure out the flash's capabilities
Signed-off-by: Stefan Tauner stefan.tauner@student.tuwien.ac.at --- ich_descriptors.c | 434 ++++++++++++++++++++++ ich_descriptors.h | 205 ++++++++++ util/ich_descriptors_tool/Makefile | 42 ++ util/ich_descriptors_tool/TODO | 6 + util/ich_descriptors_tool/ich_descriptors_tool.c | 225 +++++++++++ 5 files changed, 912 insertions(+), 0 deletions(-) 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/ich_descriptors.c b/ich_descriptors.c index ce40d9f..57c1d51 100644 --- a/ich_descriptors.c +++ b/ich_descriptors.c @@ -22,9 +22,33 @@ #if defined(__i386__) || defined(__x86_64__)
#include "ich_descriptors.h" + +#ifdef ICH_DESCRIPTORS_FROM_DUMP + +#include <stdio.h> +#define msg_perr printf +#define msg_pdbg printf +#define msg_pdbg2 printf +#define msg_pspew printf +#define print(t, ...) printf(__VA_ARGS__) +#define DESCRIPTOR_MODE_SIGNATURE 0x0ff0a55a +/* The upper map is located in the word before the 256B-long OEM section at the + * end of the 4kB-long flash descriptor. + */ +#define UPPER_MAP_OFFSET (4096 - 256 - 4) +#define getVTBA(flumap) (((flumap)->FLUMAP1 << 4) & 0x00000ff0) + +#else /* ICH_DESCRIPTORS_FROM_DUMP */ + #include "flash.h" /* for msg_* */ #include "programmer.h"
+#endif /* ICH_DESCRIPTORS_FROM_DUMP */ + +#ifndef min +#define min(a, b) (a < b) ? a : b +#endif + void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity) { print(verbosity, "BES=0x%x, ", (reg_val & VSCC_BES) >> VSCC_BES_OFF); @@ -48,6 +72,12 @@ void prettyprint_ich_descriptors(enum ich_chipset cs, const struct ich_descripto prettyprint_ich_descriptor_component(desc); prettyprint_ich_descriptor_region(desc); prettyprint_ich_descriptor_master(&desc->master); +#ifdef ICH_DESCRIPTORS_FROM_DUMP + if (cs >= CHIPSET_ICH8) { + prettyprint_ich_descriptor_upper_map(&desc->upper); + prettyprint_ich_descriptor_straps(cs, desc); + } +#endif /* ICH_DESCRIPTORS_FROM_DUMP */ }
void prettyprint_ich_descriptor_content(const struct ich_desc_content *cont) @@ -214,6 +244,409 @@ void prettyprint_ich_descriptor_master(const struct ich_desc_master *mstr) msg_pdbg2("\n"); }
+#ifdef ICH_DESCRIPTORS_FROM_DUMP + +void prettyprint_ich_descriptor_straps_ich8(const struct ich_descriptors *desc) +{ + static const char * const str_GPIO12[4] = { + "GPIO12", + "LAN PHY Power Control Function (Native Output)", + "GLAN_DOCK# (Native Input)", + "invalid configuration", + }; + + + msg_pdbg2("--- MCH details ---\n"); + msg_pdbg2("ME B is %sabled.\n", desc->north.ich8.MDB ? "dis" : "en"); + msg_pdbg2("\n"); + + msg_pdbg2("--- ICH details ---\n"); + msg_pdbg2("ME SMBus Address 1: 0x%02x\n", desc->south.ich8.ASD); + msg_pdbg2("ME SMBus Address 2: 0x%02x\n", desc->south.ich8.ASD2); + msg_pdbg2("ME SMBus Controller is connected to the %s.\n", + desc->south.ich8.MESM2SEL ? "SMLink pins" : "SMBus pins"); + msg_pdbg2("SPI CS1 is used for %s.\n", + desc->south.ich8.SPICS1_LANPHYPC_SEL ? + "LAN PHY Power Control Function" : + "SPI Chip Select"); + msg_pdbg2("GPIO12 Select is used as %s.\n", + str_GPIO12[desc->south.ich8.GPIO12_SEL]); + msg_pdbg2("PCIe Port 6 is used for %s.\n", + desc->south.ich8.GLAN_PCIE_SEL ? "integrated LAN" : "PCI Express"); + msg_pdbg2("%sn BMC Mode: " + "Intel AMT SMBus Controller 1 is connected to %s.\n", + desc->south.ich8.BMCMODE ? "I" : "Not i", + desc->south.ich8.BMCMODE ? "SMLink" : "SMBus"); + msg_pdbg2("TCO is in %s Mode.\n", + desc->south.ich8.TCOMODE ? "Advanced TCO" : "Legacy/Compatible"); + msg_pdbg2("ME A is %sabled.\n", + desc->south.ich8.ME_DISABLE ? "dis" : "en"); + msg_pdbg2("\n"); +} + +static void prettyprint_ich_descriptor_straps_ibex_pciecs(uint8_t conf, uint8_t off) +{ + msg_pdbg2("PCI Express Port Configuration Strap %d: ", off+1); + + off *= 4; + switch(conf){ + case 0: + msg_pdbg2("4x1 Ports %d-%d (x1)", 1+off, 4+off); + break; + case 1: + msg_pdbg2("1x2, 2x1 Port %d (x2), Port %d (disabled), " + "Ports %d, %d (x1)", 1+off, 2+off, 3+off, 4+off); + break; + case 2: + msg_pdbg2("2x2 Port %d (x2), Port %d (x2), Ports " + "%d, %d (disabled)", 1+off, 3+off, 2+off, 4+off); + break; + case 3: + msg_pdbg2("1x4 Port %d (x4), Ports %d-%d (disabled)", + 1+off, 2+off, 4+off); + break; + } + msg_pdbg2("\n"); +} + +void prettyprint_ich_descriptor_straps_ibex(const struct ich_desc_south_strap *s) +{ + static const uint8_t const dec_t209min[4] = { + 100, + 50, + 5, + 1 + }; + + msg_pdbg2("--- PCH ---\n"); + + /* PCHSTRP1 */ + msg_pdbg2("Chipset configuration Softstrap 2: %d\n", s->ibex.cs_ss2); + msg_pdbg2("Intel ME SMBus Select is %sabled.\n", + s->ibex.SMB_EN ? "en" : "dis"); + msg_pdbg2("SMLink0 segment is %sabled.\n", + s->ibex.SML0_EN ? "en" : "dis"); + msg_pdbg2("SMLink1 segment is %sabled.\n", + s->ibex.SML1_EN ? "en" : "dis"); + msg_pdbg2("SMLink1 Frequency: %s\n", + (s->ibex.SML1FRQ == 1) ? "100 kHz" : "reserved"); + msg_pdbg2("Intel ME SMBus Frequency: %s\n", + (s->ibex.SMB0FRQ == 1) ? "100 kHz" : "reserved"); + msg_pdbg2("SMLink0 Frequency: %s\n", + (s->ibex.SML0FRQ == 1) ? "100 kHz" : "reserved"); + msg_pdbg2("GPIO12 is used as %s.\n", s->ibex.LANPHYPC_GP12_SEL ? + "LAN_PHY_PWR_CTRL" : "general purpose output"); + + /* PCHSTRP2 */ + msg_pdbg2("Chipset configuration Softstrap 3: 0x%x\n", s->ibex.cs_ss3); + + /* PCHSTRP3 */ + msg_pdbg2("ME SMBus ASD address is %sabled.\n", + s->ibex.MESMASDEN ? "en" : "dis"); + msg_pdbg2("ME SMBus Controller ASD Target address: 0x%02x\n", + s->ibex.MESMASDA); + msg_pdbg2("ME SMBus I2C address is %sabled.\n", + s->ibex.MESMI2CEN ? "en" : "dis"); + msg_pdbg2("ME SMBus I2C target address: 0x%02x\n", + s->ibex.MESMI2CA); + + /* PCHSTRP4 */ + /* PCHSTRP5 */ + msg_pdbg2("Intel PHY is %s.\n", + (s->ibex.PHYCON == 2) ? "connected" : + (s->ibex.PHYCON == 0) ? "disconnected" : "reserved"); + msg_pdbg2("GbE MAC SMBus address is %sabled.\n", + s->ibex.GBEMAC_SMBUS_ADDR_EN ? "en" : "dis"); + msg_pdbg2("GbE MAC SMBus address: 0x%02x\n", + s->ibex.GBEMAC_SMBUS_ADDR); + msg_pdbg2("GbE PHY SMBus address: 0x%02x\n", + s->ibex.GBEPHY_SMBUS_ADDR); + + /* PCHSTRP6 */ + /* PCHSTRP7 */ + msg_pdbg2("Intel ME SMBus Subsystem Vendor ID: 0x%04x\n", + s->ibex.MESMA2UDID_VENDOR); + msg_pdbg2("Intel ME SMBus Subsystem Device ID: 0x%04x\n", + s->ibex.MESMA2UDID_VENDOR); + + /* PCHSTRP8 */ + /* PCHSTRP9 */ + prettyprint_ich_descriptor_straps_ibex_pciecs(s->ibex.PCIEPCS1, 0); + prettyprint_ich_descriptor_straps_ibex_pciecs(s->ibex.PCIEPCS1, 1); + msg_pdbg2("PCIe Lane Reversal 1: PCIe Lanes 0-3 are %sreserved.\n", + s->ibex.PCIELR1 ? "" : "not "); + msg_pdbg2("PCIe Lane Reversal 2: PCIe Lanes 4-7 are %sreserved.\n", + s->ibex.PCIELR2 ? "" : "not "); + msg_pdbg2("DMI Lane Reversal: DMI Lanes 0-3 are %sreserved.\n", + s->ibex.DMILR ? "" : "not "); + msg_pdbg2("Default PHY PCIe Port is %d.\n", s->ibex.PHY_PCIEPORTSEL+1); + msg_pdbg2("Integrated MAC/PHY communication over PCIe is %sabled.\n", + s->ibex.PHY_PCIE_EN ? "en" : "dis"); + + /* PCHSTRP10 */ + msg_pdbg2("Management Engine will boot from %sflash.\n", + s->ibex.ME_BOOT_FLASH ? "" : "ROM, then "); + msg_pdbg2("Chipset configuration Softstrap 5: %d\n", s->ibex.cs_ss5); + msg_pdbg2("Virtualization Engine Enable 1 is %sabled.\n", + s->ibex.VE_EN ? "en" : "dis"); + msg_pdbg2("ME Memory-attached Debug Display Device is %sabled.\n", + s->ibex.MMDDE ? "en" : "dis"); + msg_pdbg2("ME Memory-attached Debug Display Device address: 0x%02x\n", + s->ibex.MMADDR); + msg_pdbg2("Chipset configuration Softstrap 7: %d\n", s->ibex.cs_ss7); + msg_pdbg2("Integrated Clocking Configuration is %d.\n", + (s->ibex.ICC_SEL == 7) ? 0 : s->ibex.ICC_SEL); + msg_pdbg2("PCH Signal CL_RST1# does %sassert when Intel ME performs a " + "reset.\n", s->ibex.MER_CL1 ? "" : "not "); + + /* PCHSTRP11 */ + msg_pdbg2("SMLink1 GP Address is %sabled.\n", + s->ibex.SML1GPAEN ? "en" : "dis"); + msg_pdbg2("SMLink1 controller General Purpose Target address: 0x%02x\n", + s->ibex.SML1GPA); + msg_pdbg2("SMLink1 I2C Target address is %sabled.\n", + s->ibex.SML1I2CAEN ? "en" : "dis"); + msg_pdbg2("SMLink1 I2C Target address: 0x%02x\n", + s->ibex.SML1I2CA); + + /* PCHSTRP12 */ + /* PCHSTRP13 */ + /* PCHSTRP14 */ + msg_pdbg2("Virtualization Engine Enable 2 is %sabled.\n", + s->ibex.VE_EN2 ? "en" : "dis"); + msg_pdbg2("Virtualization Engine will boot from %sflash.\n", + s->ibex.VE_BOOT_FLASH ? "" : "ROM, then "); + msg_pdbg2("Braidwood SSD functionality is %sabled.\n", + s->ibex.BW_SSD ? "en" : "dis"); + msg_pdbg2("Braidwood NVMHCI functionality is %sabled.\n", + s->ibex.NVMHCI_EN ? "en" : "dis"); + + /* PCHSTRP15 */ + msg_pdbg2("Chipset configuration Softstrap 6: %d\n", s->ibex.cs_ss6); + msg_pdbg2("Integrated wired LAN Solution is %sabled.\n", + s->ibex.IWL_EN ? "en" : "dis"); + msg_pdbg2("t209 min Timing: %d ms\n", + dec_t209min[s->ibex.t209min]); + msg_pdbg2("\n"); +} + +void prettyprint_ich_descriptor_straps(enum ich_chipset cs, const struct ich_descriptors *desc) +{ + unsigned int i, max; + msg_pdbg2("=== Softstraps ===\n"); + + if (sizeof(desc->north.STRPs) / 4 + 1 < desc->content.MSL) { + max = sizeof(desc->north.STRPs) / 4 + 1; + msg_pdbg2("MSL (%u) is greater than the current maximum of %u " + "entries.\n", desc->content.MSL, max + 1); + msg_pdbg2("Only the first %u entries will be printed.\n", max); + } else + max = desc->content.MSL; + + msg_pdbg2("--- North/MCH/PROC (%d entries) ---\n", max); + for(i = 0; i < max; i++) + msg_pdbg2("STRP%-2d = 0x%08x\n", i, desc->north.STRPs[i]); + msg_pdbg2("\n"); + + if (sizeof(desc->south.STRPs) / 4 < desc->content.ISL) { + max = sizeof(desc->south.STRPs) / 4; + msg_pdbg2("ISL (%u) is greater than the current maximum of %u " + "entries.\n", desc->content.ISL, max); + msg_pdbg2("Only the first %u entries will be printed.\n", max); + } else + max = desc->content.ISL; + + msg_pdbg2("--- South/ICH/PCH (%d entries) ---\n", max); + for(i = 0; i < max; i++) + msg_pdbg2("STRP%-2d = 0x%08x\n", i, desc->south.STRPs[i]); + msg_pdbg2("\n"); + + switch (cs) { + case CHIPSET_ICH8: + if (sizeof(desc->north.ich8) / 4 != desc->content.MSL) + msg_pdbg2("Detailed North/MCH/PROC information is " + "probably not reliable, printing anyway.\n"); + if (sizeof(desc->south.ich8) / 4 != desc->content.ISL) + msg_pdbg2("Detailed South/ICH/PCH information is " + "probably not reliable, printing anyway.\n"); + prettyprint_ich_descriptor_straps_ich8(desc); + break; + case CHIPSET_5_SERIES_IBEX_PEAK: + /* PCH straps only. PROCSTRPs are unknown. */ + if (sizeof(desc->south.ibex) / 4 != desc->content.ISL) + msg_pdbg2("Detailed South/ICH/PCH information is " + "probably not reliable, printing anyway.\n"); + prettyprint_ich_descriptor_straps_ibex(&desc->south); + break; + case CHIPSET_ICH_UNKNOWN: + break; + default: + msg_pdbg2("The meaning of the descriptor straps are unknown " + "yet.\n\n"); + 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_pdbg2("Manufacturer ID 0x%02x, Device ID 0x%04x\n", mid, did); +} + +void prettyprint_ich_descriptor_upper_map(const struct ich_desc_upper_map *umap) +{ + int i; + msg_pdbg2("=== Upper Map Section ===\n"); + msg_pdbg2("FLUMAP1 0x%08x\n", umap->FLUMAP1); + msg_pdbg2("\n"); + + msg_pdbg2("--- Details ---\n"); + msg_pdbg2("VTL (length in DWORDS) = %d\n", umap->VTL); + msg_pdbg2("VTBA (base address) = 0x%6.6x\n", getVTBA(umap)); + msg_pdbg2("\n"); + + msg_pdbg2("VSCC Table: %d entries\n", umap->VTL/2); + for (i = 0; i < umap->VTL/2; i++) + { + uint32_t jid = umap->vscc_table[i].JID; + uint32_t vscc = umap->vscc_table[i].VSCC; + msg_pdbg2(" JID%d = 0x%08x\n", i, jid); + msg_pdbg2(" VSCC%d = 0x%08x\n", i, vscc); + msg_pdbg2(" "); /* indention */ + prettyprint_rdid(jid); + msg_pdbg2(" "); /* indention */ + prettyprint_ich_reg_vscc(vscc, 0); + } + msg_pdbg2("\n"); +} + +/* len is the length of dump in bytes */ +int read_ich_descriptors_from_dump(const uint32_t *dump, unsigned int len, enum ich_chipset cs, struct ich_descriptors *desc) +{ + unsigned int i, max; + uint8_t pch_bug_offset = 0; + + if (dump == NULL || desc == NULL) + return RET_PARAM; + + if (dump[0] != DESCRIPTOR_MODE_SIGNATURE) { + if (dump[4] == DESCRIPTOR_MODE_SIGNATURE) + pch_bug_offset = 4; + else + return RET_ERR; + } + + /* map */ + if (len < (4 + pch_bug_offset) * 4 - 1) + return RET_OOB; + desc->content.FLVALSIG = dump[0 + pch_bug_offset]; + desc->content.FLMAP0 = dump[1 + pch_bug_offset]; + desc->content.FLMAP1 = dump[2 + pch_bug_offset]; + desc->content.FLMAP2 = dump[3 + pch_bug_offset]; + + /* component */ + if (len < (getFCBA(&desc->content) + 3 * 4 - 1)) + return RET_OOB; + desc->component.FLCOMP = dump[(getFCBA(&desc->content) >> 2) + 0]; + desc->component.FLILL = dump[(getFCBA(&desc->content) >> 2) + 1]; + desc->component.FLPB = dump[(getFCBA(&desc->content) >> 2) + 2]; + + /* region */ + if (len < (getFRBA(&desc->content) + 5 * 4 - 1)) + return RET_OOB; + desc->region.FLREGs[0] = dump[(getFRBA(&desc->content) >> 2) + 0]; + desc->region.FLREGs[1] = dump[(getFRBA(&desc->content) >> 2) + 1]; + desc->region.FLREGs[2] = dump[(getFRBA(&desc->content) >> 2) + 2]; + desc->region.FLREGs[3] = dump[(getFRBA(&desc->content) >> 2) + 3]; + desc->region.FLREGs[4] = dump[(getFRBA(&desc->content) >> 2) + 4]; + + /* master */ + if (len < (getFMBA(&desc->content) + 3 * 4 - 1)) + return RET_OOB; + desc->master.FLMSTR1 = dump[(getFMBA(&desc->content) >> 2) + 0]; + desc->master.FLMSTR2 = dump[(getFMBA(&desc->content) >> 2) + 1]; + desc->master.FLMSTR3 = dump[(getFMBA(&desc->content) >> 2) + 2]; + + /* upper map */ + desc->upper.FLUMAP1 = dump[(UPPER_MAP_OFFSET >> 2) + 0]; + + /* VTL is 8 bits long. Quote from the Ibex Peak SPI programming guide: + * "Identifies the 1s based number of DWORDS contained in the VSCC + * Table. Each SPI component entry in the table is 2 DWORDS long." So + * the maximum of 255 gives us 127.5 SPI components(!?) 8 bytes each. A + * check ensures that the maximum offset actually accessed is available. + */ + if (len < (getVTBA(&desc->upper) + (desc->upper.VTL / 2 * 8) - 1)) + return RET_OOB; + + for (i = 0; i < desc->upper.VTL/2; i++) { + desc->upper.vscc_table[i].JID = + dump[(getVTBA(&desc->upper) >> 2) + i * 2 + 0]; + desc->upper.vscc_table[i].VSCC = + dump[(getVTBA(&desc->upper) >> 2) + i * 2 + 1]; + } + + /* MCH/PROC (aka. North) straps */ + if (len < getFMSBA(&desc->content) + desc->content.MSL * 4) + return RET_OOB; + + /* limit the range to be written */ + max = min(sizeof(desc->north.STRPs) / 4, desc->content.MSL); + for (i = 0; i < max; i++) + desc->north.STRPs[i] = + dump[(getFMSBA(&desc->content) >> 2) + i]; + + /* ICH/PCH (aka. South) straps */ + if (len < getFISBA(&desc->content) + desc->content.ISL * 4) + return RET_OOB; + + /* limit the range to be written */ + max = min(sizeof(desc->south.STRPs) / 4, desc->content.ISL); + for (i = 0; i < max; i++) + desc->south.STRPs[i] = + dump[(getFISBA(&desc->content) >> 2) + i]; + + return RET_OK; +} + +#else /* ICH_DESCRIPTORS_FROM_DUMP */ + +/** Returns the integer representation of the component density with index +idx in bytes or 0 if a correct size can not be determined. */ +int getFCBA_component_density(uint8_t idx, const struct ich_descriptors *desc) +{ + uint8_t size_enc; + static const int const dec_mem[6] = { + 512 * 1024, + 1 * 1024 * 1024, + 2 * 1024 * 1024, + 4 * 1024 * 1024, + 8 * 1024 * 1024, + 16 * 1024 * 1024, + }; + + switch(idx) { + case 0: + size_enc = desc->component.comp1_density; + break; + case 1: + if (desc->content.NC == 0) + return 0; + size_enc = desc->component.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 is invalid. " + "Encoded density is 0x%x.\n", idx, size_enc); + return 0; + } + return dec_mem[size_enc]; +} + static uint32_t read_descriptor_reg(uint8_t section, uint16_t offset, void *spibar) { uint32_t control = 0; @@ -284,5 +717,6 @@ int read_ich_descriptors_via_fdo(void *spibar, struct ich_descriptors *desc) msg_pdbg2(" done.\n"); return RET_OK; } +#endif /* ICH_DESCRIPTORS_FROM_DUMP */ #endif /* BITFIELDS == 1 */ #endif /* defined(__i386__) || defined(__x86_64__) */ diff --git a/ich_descriptors.h b/ich_descriptors.h index b1da914..56d1b3e 100644 --- a/ich_descriptors.h +++ b/ich_descriptors.h @@ -240,11 +240,206 @@ struct ich_desc_master { }; };
+#ifdef ICH_DESCRIPTORS_FROM_DUMP +struct ich_desc_north_strap { + union { + uint32_t STRPs[1]; /* current maximum: ich8 */ + struct { /* ich8 */ + struct { /* STRP2 (in the datasheet) */ + uint32_t MDB :1, + :31; + }; + } ich8; + }; +}; + +struct ich_desc_south_strap { + union { + uint32_t STRPs[16]; /* current maximum: ibex peak */ + struct { /* ich8 */ + struct { /* STRP1 */ + uint32_t ME_DISABLE :1, + :6, + TCOMODE :1, + ASD :7, + BMCMODE :1, + :3, + GLAN_PCIE_SEL :1, + GPIO12_SEL :2, + SPICS1_LANPHYPC_SEL :1, + MESM2SEL :1, + :1, + ASD2 :7; + }; + } ich8; + struct { /* ibex peak */ + struct { /* STRP0 */ + uint32_t :1, + cs_ss2 :1, + :5, + SMB_EN :1, + SML0_EN :1, + SML1_EN :1, + SML1FRQ :2, + SMB0FRQ :2, + SML0FRQ :2, + :4, + LANPHYPC_GP12_SEL :1, + cs_ss1 :1, + :2, + DMI_REQID_DIS :1, + :4, + BBBS :2, + :1; + }; + struct { /* STRP1 */ + uint32_t cs_ss3 :4, + :28; + }; + struct { /* STRP2 */ + uint32_t :8, + MESMASDEN :1, + MESMASDA :7, + :8, + MESMI2CEN :1, + MESMI2CA :7; + }; + struct { /* STRP3 */ + uint32_t :32; + }; + struct { /* STRP4 */ + uint32_t PHYCON :2, + :6, + GBEMAC_SMBUS_ADDR_EN :1, + GBEMAC_SMBUS_ADDR :7, + :1, + GBEPHY_SMBUS_ADDR :7, + :8; + }; + struct { /* STRP5 */ + uint32_t :32; + }; + struct { /* STRP6 */ + uint32_t :32; + }; + struct { /* STRP7 */ + uint32_t MESMA2UDID_VENDOR :16, + MESMA2UDID_DEVICE :16; + }; + struct { /* STRP8 */ + uint32_t :32; + }; + struct { /* STRP9 */ + uint32_t PCIEPCS1 :2, + PCIEPCS2 :2, + PCIELR1 :1, + PCIELR2 :1, + DMILR :1, + :1, + PHY_PCIEPORTSEL :3, + PHY_PCIE_EN :1, + :20; + }; + struct { /* STRP10 */ + uint32_t :1, + ME_BOOT_FLASH :1, + cs_ss5 :1, + VE_EN :1, + :4, + MMDDE :1, + MMADDR :7, + cs_ss7 :1, + :1, + ICC_SEL :3, + MER_CL1 :1, + :10; + }; + struct { /* STRP11 */ + uint32_t SML1GPAEN :1, + SML1GPA :7, + :16, + SML1I2CAEN :1, + SML1I2CA :7; + }; + struct { /* STRP12 */ + uint32_t :32; + }; + struct { /* STRP13 */ + uint32_t :32; + }; + struct { /* STRP14 */ + uint32_t :8, + VE_EN2 :1, + :5, + VE_BOOT_FLASH :1, + :1, + BW_SSD :1, + NVMHCI_EN :1, + :14; + }; + struct { /* STRP15 */ + uint32_t :3, + cs_ss6 :2, + :1, + IWL_EN :1, + :1, + t209min :2, + :22; + }; + }ibex; + }; +}; + +struct ich_desc_upper_map { + union { + uint32_t FLUMAP1; /* Flash Upper Map 1 */ + struct { + uint32_t VTBA :8, /* ME VSCC Table Base Address */ + VTL :8, /* ME VSCC Table Length */ + :16; + }; + }; + struct { + union { /* JEDEC-ID Register */ + uint32_t JID; + struct { + uint32_t vid :8, /* Vendor ID */ + cid0 :8, /* Component ID 0 */ + cid1 :8, /* Component ID 1 */ + :8; + }; + }; + union { /* Vendor Specific Component Capabilities */ + uint32_t VSCC; + struct { + uint32_t ubes :2, /* Upper Block/Sector Erase Size */ + uwg :1, /* Upper Write Granularity */ + uwsr :1, /* Upper Write Status Required */ + uwews :1, /* Upper Write Enable on Write Status */ + :3, + ueo :8, /* Upper Erase Opcode */ + lbes :2, /* Lower Block/Sector Erase Size */ + lwg :1, /* Lower Write Granularity */ + lwsr :1, /* Lower Write Status Required */ + lwews :1, /* Lower Write Enable on Write Status */ + :3, + leo :16; /* Lower Erase Opcode */ + }; + }; + } vscc_table[128]; +}; +#endif /* ICH_DESCRIPTORS_FROM_DUMP */ + struct ich_descriptors { struct ich_desc_content content; struct ich_desc_component component; struct ich_desc_region region; struct ich_desc_master master; +#ifdef ICH_DESCRIPTORS_FROM_DUMP + struct ich_desc_north_strap north; + struct ich_desc_south_strap south; + struct ich_desc_upper_map upper; +#endif /* ICH_DESCRIPTORS_FROM_DUMP */ };
void prettyprint_ich_descriptors(enum ich_chipset, const struct ich_descriptors *desc); @@ -254,8 +449,18 @@ void prettyprint_ich_descriptor_component(const struct ich_descriptors *desc); void prettyprint_ich_descriptor_region(const struct ich_descriptors *desc); void prettyprint_ich_descriptor_master(const struct ich_desc_master *master);
+#ifdef ICH_DESCRIPTORS_FROM_DUMP + +void prettyprint_ich_descriptor_upper_map(const struct ich_desc_upper_map *umap); +void prettyprint_ich_descriptor_straps(enum ich_chipset cs, const struct ich_descriptors *desc); +int read_ich_descriptors_from_dump(const uint32_t *dump, unsigned int len, enum ich_chipset cs, struct ich_descriptors *desc); + +#else /* ICH_DESCRIPTORS_FROM_DUMP */ + int read_ich_descriptors_via_fdo(void *spibar, struct ich_descriptors *desc); +int getFCBA_component_density(uint8_t idx, const struct ich_descriptors *desc);
+#endif /* ICH_DESCRIPTORS_FROM_DUMP */ #endif /* BITFIELDS == 1 */ #endif /* __ICH_DESCRIPTORS_H__ */ #endif /* defined(__i386__) || defined(__x86_64__) */ diff --git a/util/ich_descriptors_tool/Makefile b/util/ich_descriptors_tool/Makefile new file mode 100644 index 0000000..1af90ce --- /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 binary dumps +CFLAGS += -D ICH_DESCRIPTORS_FROM_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 share source files without simultaneously sharing .o files +# with flashrom, which would lead to unexpected results (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..03701bf --- /dev/null +++ b/util/ich_descriptors_tool/TODO @@ -0,0 +1,6 @@ +- 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 +- little endian only 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..3721eb4 --- /dev/null +++ b/util/ich_descriptors_tool/ich_descriptors_tool.c @@ -0,0 +1,225 @@ +/* + * 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 + */ + +/* + * dump information and binaries from BIOS images that are in descriptor mode + */ +#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 "ich_descriptors.h" + +static void dump_file(const char *basename, const uint32_t *dump, unsigned int len, struct ich_desc_region *reg, unsigned int i) +{ + int ret; + char *fn; + const char *reg_name; + uint32_t file_len; + const char *const region_names[5] = { + "Descriptor", "BIOS", "ME", "GbE", "Platform" + }; + uint32_t base = ICH_FREG_BASE(reg->FLREGs[i]); + uint32_t limit = ICH_FREG_LIMIT(reg->FLREGs[i]); + + reg_name = region_names[i]; + if (base > limit) { + printf("The %s region is unused and thus not dumped.\n", + reg_name); + return; + } + + limit = limit | 0x0fff; + file_len = limit + 1 - base; + if (base + file_len > len) { + printf("The %s region is spanning 0x%08x-0x%08x, but it is " + "not (fully) included in the image (0-0x%08x), thus not " + "dumped.\n", reg_name, base, limit, len - 1); + return; + } + + fn = malloc(strlen(basename) + strlen(reg_name) + strlen(".bin") + 2); + if (!fn) { + fprintf(stderr, "Out of memory!\n"); + exit(1); + } + snprintf(fn, strlen(basename) + strlen(reg_name) + strlen(".bin") + 2, + "%s.%s.bin", basename, reg_name); + printf("Dumping %u bytes of the %s region from 0x%08x-0x%08x to %s... ", + file_len, region_names[i], base, limit, fn); + int fh = open(fn, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + free(fn); + if (fh < 0) { + fprintf(stderr, + "ERROR: couldn't open(%s): %s\n", fn, strerror(errno)); + exit(1); + } + + ret = write(fh, &dump[base >> 2], file_len); + if (ret != file_len) { + fprintf(stderr, "FAILED.\n"); + exit(1); + } + + printf("done.\n"); + close(fh); +} + +void dump_files(const char *n, const uint32_t *buf, unsigned int len, struct ich_desc_region *reg) +{ + unsigned int i; + printf("=== Dumping region files ===\n"); + for (i = 0; i < 5; i++) + dump_file(n, buf, len, reg, i); + printf("\n"); +} + +static void usage(char *argv[], char *error) +{ + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + printf("usage: '%s -f <image file name> [-c <chipset name>] [-d]'\n\n" +"where <image file name> points to an image of the contents of the SPI flash.\n" +"In case that image is really in descriptor mode %s\n" +"will pretty print some of the contained information.\n" +"To also print the data stored in the descriptor strap you have to indicate\n" +"the chipset series with the '-c' parameter and one of the possible arguments:\n" +"\t- "ich8",\n" +"\t- "ich9",\n" +"\t- "ich10",\n" +"\t- "5" or "ibex" for Intel's 5 series chipsets,\n" +"\t- "6" or "cougar" for Intel's 6 series chipsets,\n" +"\t- "7" or "panther" for Intel's 7 series chipsets.\n" +"If '-d' is specified some regions such as the BIOS image as seen by the CPU or\n" +"the GbE blob that is required to initialize the GbE are also dumped to files.\n", + argv[0], argv[0]); + exit(1); +} + +int main(int argc, char *argv[]) +{ + int fd; /* file descriptor to flash file */ + int len; /* file/buffer size in bytes */ + uint32_t *buf; /* mmap'd file */ + + int opt; + int ret; + int dump = 0; + const char *fn = NULL; + const char *csn = NULL; + enum ich_chipset cs = CHIPSET_ICH_UNKNOWN; + struct ich_descriptors desc = {{ 0 }}; + + while ((opt = getopt(argc, argv, "df:c:")) != -1) { + switch (opt) { + case 'd': + dump = 1; + break; + case 'f': + fn = optarg; + break; + case 'c': + csn = optarg; + break; + default: /* '?' */ + usage(argv, NULL); + } + } + if (fn == NULL) + usage(argv, + "Need a file name of a descriptor image to read from."); + + fd = open(fn, O_RDONLY); + if (fd < 0) + usage(argv, "No such file"); + len = lseek(fd, 0, SEEK_END); + if (len < 0) + usage(argv, "Seeking to the end of the file failed"); + + buf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); + if (buf == (void *) -1) { + /* fallback for stupid OSes like cygwin */ + int ret; + buf = malloc(len); + if (!buf) + usage(argv, "Could not allocate memory"); + lseek(fd, 0, SEEK_SET); + ret = read(fd, buf, len); + if (ret != len) + usage(argv, "Seeking to the end of the file failed"); + } + printf("The flash image has a size of %d [0x%x] bytes.\n", len, len); + close(fd); + + if (csn != NULL) { + if (strcmp(csn, "ich8") == 0) + cs = CHIPSET_ICH8; + else if (strcmp(csn, "ich9") == 0) + cs = CHIPSET_ICH9; + else if (strcmp(csn, "ich10") == 0) + cs = CHIPSET_ICH10; + else if ((strcmp(csn, "5") == 0) || + (strcmp(csn, "ibex") == 0)) + cs = CHIPSET_5_SERIES_IBEX_PEAK; + else if ((strcmp(csn, "6") == 0) || + (strcmp(csn, "cougar") == 0)) + cs = CHIPSET_6_SERIES_COUGAR_POINT; + else if ((strcmp(csn, "7") == 0) || + (strcmp(csn, "panther") == 0)) + cs = CHIPSET_7_SERIES_PANTHER_POINT; + } + + ret = read_ich_descriptors_from_dump(buf, len, cs, &desc); + switch (ret) { + case RET_OK: + break; + case RET_ERR: + printf("Image not in descriptor mode.\n"); + exit(1); + case RET_OOB: + printf("Tried to access a location out of bounds of the image. " + "- Corrupt image?\n"); + exit(1); + default: + printf("Unhandled return value at %s:%u, please report this.\n", + __FILE__, __LINE__); + exit(1); + } + + prettyprint_ich_descriptors(cs, &desc); + + //uint8_t *pMAC = (uint8_t *) &buf[r->reg3_base >> 2]; + //printf("The MAC-address might be: %02x:%02x:%02x:%02x:%02x:%02x\n", + //pMAC[0], pMAC[1], pMAC[2], pMAC[3], pMAC[4], pMAC[5]); + + if (dump == 1) + dump_files(fn, buf, len, &desc.region); + + return 0; +} +