diff --git a/ich_descriptors.c b/ich_descriptors.c index 4c18dfa39..a2aa94024 100644 --- a/ich_descriptors.c +++ b/ich_descriptors.c @@ -42,6 +42,36 @@ #define min(a, b) (((a) < (b)) ? (a) : (b)) #endif +ssize_t ich_number_of_regions(const enum ich_chipset cs, const struct ich_desc_content *const cont) +{ + switch (cs) { + case CHIPSET_100_SERIES_SUNRISE_POINT: + return 10; + case CHIPSET_9_SERIES_WILDCAT_POINT_LP: + case CHIPSET_9_SERIES_WILDCAT_POINT: + case CHIPSET_8_SERIES_LYNX_POINT_LP: + case CHIPSET_8_SERIES_LYNX_POINT: + case CHIPSET_8_SERIES_WELLSBURG: + if (cont->NR <= 6) + return cont->NR + 1; + else + return -1; + default: + if (cont->NR <= 4) + return cont->NR + 1; + else + return -1; + } +} + +ssize_t ich_number_of_masters(const enum ich_chipset cs, const struct ich_desc_content *const cont) +{ + if (cont->NM < MAX_NUM_MASTERS) + return cont->NM + 1; + else + return -1; +} + void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity, bool print_vcl) { print(verbosity, "BES=0x%x, ", (reg_val & VSCC_BES) >> VSCC_BES_OFF); @@ -62,10 +92,10 @@ void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity, bool print_vcl) void prettyprint_ich_descriptors(enum ich_chipset cs, const struct ich_descriptors *desc) { - prettyprint_ich_descriptor_content(&desc->content); + prettyprint_ich_descriptor_content(cs, &desc->content); prettyprint_ich_descriptor_component(cs, desc); - prettyprint_ich_descriptor_region(desc); - prettyprint_ich_descriptor_master(&desc->master); + prettyprint_ich_descriptor_region(cs, desc); + prettyprint_ich_descriptor_master(cs, desc); #ifdef ICH_DESCRIPTORS_FROM_DUMP_ONLY if (cs >= CHIPSET_ICH8) { prettyprint_ich_descriptor_upper_map(&desc->upper); @@ -74,7 +104,7 @@ void prettyprint_ich_descriptors(enum ich_chipset cs, const struct ich_descripto #endif /* ICH_DESCRIPTORS_FROM_DUMP_ONLY */ } -void prettyprint_ich_descriptor_content(const struct ich_desc_content *cont) +void prettyprint_ich_descriptor_content(enum ich_chipset cs, const struct ich_desc_content *cont) { msg_pdbg2("=== Content Section ===\n"); msg_pdbg2("FLVALSIG 0x%08x\n", cont->FLVALSIG); @@ -84,16 +114,16 @@ void prettyprint_ich_descriptor_content(const struct ich_desc_content *cont) msg_pdbg2("\n"); msg_pdbg2("--- Details ---\n"); - msg_pdbg2("NR (Number of Regions): %5d\n", cont->NR + 1); - msg_pdbg2("FRBA (Flash Region Base Address): 0x%03x\n", getFRBA(cont)); - msg_pdbg2("NC (Number of Components): %5d\n", cont->NC + 1); - msg_pdbg2("FCBA (Flash Component Base Address): 0x%03x\n", getFCBA(cont)); - msg_pdbg2("ISL (ICH/PCH Strap Length): %5d\n", cont->ISL); - msg_pdbg2("FISBA/FPSBA (Flash ICH/PCH Strap Base Address): 0x%03x\n", getFISBA(cont)); - msg_pdbg2("NM (Number of Masters): %5d\n", cont->NM + 1); - msg_pdbg2("FMBA (Flash Master Base Address): 0x%03x\n", getFMBA(cont)); - msg_pdbg2("MSL/PSL (MCH/PROC Strap Length): %5d\n", cont->MSL); - msg_pdbg2("FMSBA (Flash MCH/PROC Strap Base Address): 0x%03x\n", getFMSBA(cont)); + msg_pdbg2("NR (Number of Regions): %5zd\n", ich_number_of_regions(cs, cont)); + msg_pdbg2("FRBA (Flash Region Base Address): 0x%03x\n", getFRBA(cont)); + msg_pdbg2("NC (Number of Components): %5d\n", cont->NC + 1); + msg_pdbg2("FCBA (Flash Component Base Address): 0x%03x\n", getFCBA(cont)); + msg_pdbg2("ISL (ICH/PCH Strap Length): %5d\n", cont->ISL); + msg_pdbg2("FISBA/FPSBA (Flash ICH/PCH Strap Base Address): 0x%03x\n", getFISBA(cont)); + msg_pdbg2("NM (Number of Masters): %5zd\n", ich_number_of_masters(cs, cont)); + msg_pdbg2("FMBA (Flash Master Base Address): 0x%03x\n", getFMBA(cont)); + msg_pdbg2("MSL/PSL (MCH/PROC Strap Length): %5d\n", cont->MSL); + msg_pdbg2("FMSBA (Flash MCH/PROC Strap Base Address): 0x%03x\n", getFMSBA(cont)); msg_pdbg2("\n"); } @@ -140,7 +170,8 @@ static const char *pprint_density(enum ich_chipset cs, const struct ich_descript case CHIPSET_8_SERIES_LYNX_POINT_LP: case CHIPSET_8_SERIES_WELLSBURG: case CHIPSET_9_SERIES_WILDCAT_POINT: - case CHIPSET_9_SERIES_WILDCAT_POINT_LP: { + case CHIPSET_9_SERIES_WILDCAT_POINT_LP: + case CHIPSET_100_SERIES_SUNRISE_POINT: { uint8_t size_enc; if (idx == 0) { size_enc = desc->component.dens_new.comp1_density; @@ -159,7 +190,7 @@ static const char *pprint_density(enum ich_chipset cs, const struct ich_descript static const char *pprint_freq(enum ich_chipset cs, uint8_t value) { - static const char * const freq_str[8] = { + static const char *const freq_str[2][8] = { { "20 MHz", /* 000 */ "33 MHz", /* 001 */ "reserved", /* 010 */ @@ -168,7 +199,16 @@ static const char *pprint_freq(enum ich_chipset cs, uint8_t value) "reserved", /* 101 */ "reserved", /* 110 */ "reserved" /* 111 */ - }; + }, { + "reserved", /* 000 */ + "reserved", /* 001 */ + "48 MHz", /* 010 */ + "reserved", /* 011 */ + "30 MHz", /* 100 */ + "reserved", /* 101 */ + "17 MHz", /* 110 */ + "reserved" /* 111 */ + } }; switch (cs) { case CHIPSET_ICH8: @@ -185,7 +225,9 @@ static const char *pprint_freq(enum ich_chipset cs, uint8_t value) case CHIPSET_8_SERIES_WELLSBURG: case CHIPSET_9_SERIES_WILDCAT_POINT: case CHIPSET_9_SERIES_WILDCAT_POINT_LP: - return freq_str[value]; + return freq_str[0][value]; + case CHIPSET_100_SERIES_SUNRISE_POINT: + return freq_str[1][value]; case CHIPSET_ICH_UNKNOWN: default: return "unknown"; @@ -198,6 +240,8 @@ void prettyprint_ich_descriptor_component(enum ich_chipset cs, const struct ich_ msg_pdbg2("=== Component Section ===\n"); msg_pdbg2("FLCOMP 0x%08x\n", desc->component.FLCOMP); msg_pdbg2("FLILL 0x%08x\n", desc->component.FLILL ); + if (cs == CHIPSET_100_SERIES_SUNRISE_POINT) + msg_pdbg2("FLILL1 0x%08x\n", desc->component.FLILL1); msg_pdbg2("\n"); msg_pdbg2("--- Details ---\n"); @@ -216,9 +260,10 @@ void prettyprint_ich_descriptor_component(enum ich_chipset cs, const struct ich_ if (cs > CHIPSET_6_SERIES_COUGAR_POINT) msg_pdbg2("Dual Output Fast Read Support: %sabled\n", desc->component.modes.dual_output ? "dis" : "en"); - if (desc->component.FLILL == 0) + if (desc->component.FLILL == 0 && + (cs != CHIPSET_100_SERIES_SUNRISE_POINT || desc->component.FLILL1 == 0)) { msg_pdbg2("No forbidden opcodes.\n"); - else { + } else { msg_pdbg2("Invalid instruction 0: 0x%02x\n", desc->component.invalid_instr0); msg_pdbg2("Invalid instruction 1: 0x%02x\n", @@ -227,76 +272,116 @@ void prettyprint_ich_descriptor_component(enum ich_chipset cs, const struct ich_ desc->component.invalid_instr2); msg_pdbg2("Invalid instruction 3: 0x%02x\n", desc->component.invalid_instr3); + if (cs == CHIPSET_100_SERIES_SUNRISE_POINT) { + msg_pdbg2("Invalid instruction 4: 0x%02x\n", + desc->component.invalid_instr4); + msg_pdbg2("Invalid instruction 5: 0x%02x\n", + desc->component.invalid_instr5); + msg_pdbg2("Invalid instruction 6: 0x%02x\n", + desc->component.invalid_instr6); + msg_pdbg2("Invalid instruction 7: 0x%02x\n", + desc->component.invalid_instr7); + } } msg_pdbg2("\n"); } static void pprint_freg(const struct ich_desc_region *reg, uint32_t i) { - static const char *const region_names[5] = { - "Descr.", "BIOS", "ME", "GbE", "Platf." + static const char *const region_names[] = { + "Descr.", "BIOS", "ME", "GbE", "Platf.", "unknown", "unknown", "unknown", + "EC", "unknown", }; - if (i >= 5) { + if (i >= ARRAY_SIZE(region_names)) { msg_pdbg2("%s: region index too high.\n", __func__); return; } uint32_t base = ICH_FREG_BASE(reg->FLREGs[i]); uint32_t limit = ICH_FREG_LIMIT(reg->FLREGs[i]); - msg_pdbg2("Region %d (%-6s) ", i, region_names[i]); + msg_pdbg2("Region %d (%-7s) ", i, region_names[i]); if (base > limit) msg_pdbg2("is unused.\n"); else msg_pdbg2("0x%08x - 0x%08x\n", base, limit); } -void prettyprint_ich_descriptor_region(const struct ich_descriptors *desc) +void prettyprint_ich_descriptor_region(const enum ich_chipset cs, const struct ich_descriptors *const desc) { - uint8_t i; - uint8_t nr = desc->content.NR + 1; + size_t i; + const ssize_t nr = ich_number_of_regions(cs, &desc->content); msg_pdbg2("=== Region Section ===\n"); - if (nr > 5) { + if (nr < 0) { msg_pdbg2("%s: number of regions too high (%d).\n", __func__, - nr); + desc->content.NR + 1); return; } - for (i = 0; i < 5; i++) - msg_pdbg2("FLREG%d 0x%08x\n", i, desc->region.FLREGs[i]); + for (i = 0; i < nr; i++) + msg_pdbg2("FLREG%zu 0x%08x\n", i, desc->region.FLREGs[i]); msg_pdbg2("\n"); msg_pdbg2("--- Details ---\n"); - for (i = 0; i < 5; i++) + for (i = 0; i < nr; i++) pprint_freg(&desc->region, i); msg_pdbg2("\n"); } -void prettyprint_ich_descriptor_master(const struct ich_desc_master *mstr) +void prettyprint_ich_descriptor_master(const enum ich_chipset cs, const struct ich_descriptors *const desc) { + size_t i; + const ssize_t nm = ich_number_of_masters(cs, &desc->content); msg_pdbg2("=== Master Section ===\n"); - msg_pdbg2("FLMSTR1 0x%08x\n", mstr->FLMSTR1); - msg_pdbg2("FLMSTR2 0x%08x\n", mstr->FLMSTR2); - msg_pdbg2("FLMSTR3 0x%08x\n", mstr->FLMSTR3); + if (nm < 0) { + msg_pdbg2("%s: number of masters too high (%d).\n", __func__, + desc->content.NM + 1); + return; + } + for (i = 0; i < nm; i++) + msg_pdbg2("FLMSTR%zu 0x%08x\n", i + 1, desc->master.FLMSTRs[i]); msg_pdbg2("\n"); msg_pdbg2("--- Details ---\n"); - msg_pdbg2(" Descr. BIOS ME GbE Platf.\n"); - msg_pdbg2("BIOS %c%c %c%c %c%c %c%c %c%c\n", - (mstr->BIOS_descr_r) ?'r':' ', (mstr->BIOS_descr_w) ?'w':' ', - (mstr->BIOS_BIOS_r) ?'r':' ', (mstr->BIOS_BIOS_w) ?'w':' ', - (mstr->BIOS_ME_r) ?'r':' ', (mstr->BIOS_ME_w) ?'w':' ', - (mstr->BIOS_GbE_r) ?'r':' ', (mstr->BIOS_GbE_w) ?'w':' ', - (mstr->BIOS_plat_r) ?'r':' ', (mstr->BIOS_plat_w) ?'w':' '); - msg_pdbg2("ME %c%c %c%c %c%c %c%c %c%c\n", - (mstr->ME_descr_r) ?'r':' ', (mstr->ME_descr_w) ?'w':' ', - (mstr->ME_BIOS_r) ?'r':' ', (mstr->ME_BIOS_w) ?'w':' ', - (mstr->ME_ME_r) ?'r':' ', (mstr->ME_ME_w) ?'w':' ', - (mstr->ME_GbE_r) ?'r':' ', (mstr->ME_GbE_w) ?'w':' ', - (mstr->ME_plat_r) ?'r':' ', (mstr->ME_plat_w) ?'w':' '); - msg_pdbg2("GbE %c%c %c%c %c%c %c%c %c%c\n", - (mstr->GbE_descr_r) ?'r':' ', (mstr->GbE_descr_w) ?'w':' ', - (mstr->GbE_BIOS_r) ?'r':' ', (mstr->GbE_BIOS_w) ?'w':' ', - (mstr->GbE_ME_r) ?'r':' ', (mstr->GbE_ME_w) ?'w':' ', - (mstr->GbE_GbE_r) ?'r':' ', (mstr->GbE_GbE_w) ?'w':' ', - (mstr->GbE_plat_r) ?'r':' ', (mstr->GbE_plat_w) ?'w':' '); + if (cs == CHIPSET_100_SERIES_SUNRISE_POINT) { + const char *const master_names[] = { + "BIOS", "ME", "GbE", "unknown", "EC", + }; + if (nm >= ARRAY_SIZE(master_names)) { + msg_pdbg2("%s: number of masters too high (%d).\n", __func__, + desc->content.NM + 1); + return; + } + + msg_pdbg2(" FD BIOS ME GbE Pltf Reg5 Reg6 Reg7 EC Reg9\n"); + for (i = 0; i < nm; i++) { + size_t j; + msg_pdbg2("%-4s", master_names[i]); + for (j = 0; j < 10; j++) + msg_pdbg2(" %c%c ", + desc->master.mstr[i].read & (1 << j) ? 'r' : ' ', + desc->master.mstr[i].write & (1 << j) ? 'w' : ' '); + msg_pdbg2("\n"); + } + } else { + const struct ich_desc_master *const mstr = &desc->master; + msg_pdbg2(" Descr. BIOS ME GbE Platf.\n"); + msg_pdbg2("BIOS %c%c %c%c %c%c %c%c %c%c\n", + (mstr->BIOS_descr_r) ?'r':' ', (mstr->BIOS_descr_w) ?'w':' ', + (mstr->BIOS_BIOS_r) ?'r':' ', (mstr->BIOS_BIOS_w) ?'w':' ', + (mstr->BIOS_ME_r) ?'r':' ', (mstr->BIOS_ME_w) ?'w':' ', + (mstr->BIOS_GbE_r) ?'r':' ', (mstr->BIOS_GbE_w) ?'w':' ', + (mstr->BIOS_plat_r) ?'r':' ', (mstr->BIOS_plat_w) ?'w':' '); + msg_pdbg2("ME %c%c %c%c %c%c %c%c %c%c\n", + (mstr->ME_descr_r) ?'r':' ', (mstr->ME_descr_w) ?'w':' ', + (mstr->ME_BIOS_r) ?'r':' ', (mstr->ME_BIOS_w) ?'w':' ', + (mstr->ME_ME_r) ?'r':' ', (mstr->ME_ME_w) ?'w':' ', + (mstr->ME_GbE_r) ?'r':' ', (mstr->ME_GbE_w) ?'w':' ', + (mstr->ME_plat_r) ?'r':' ', (mstr->ME_plat_w) ?'w':' '); + msg_pdbg2("GbE %c%c %c%c %c%c %c%c %c%c\n", + (mstr->GbE_descr_r) ?'r':' ', (mstr->GbE_descr_w) ?'w':' ', + (mstr->GbE_BIOS_r) ?'r':' ', (mstr->GbE_BIOS_w) ?'w':' ', + (mstr->GbE_ME_r) ?'r':' ', (mstr->GbE_ME_w) ?'w':' ', + (mstr->GbE_GbE_r) ?'r':' ', (mstr->GbE_GbE_w) ?'w':' ', + (mstr->GbE_plat_r) ?'r':' ', (mstr->GbE_plat_w) ?'w':' '); + } msg_pdbg2("\n"); } @@ -739,8 +824,8 @@ static enum ich_chipset guess_ich_chipset_from_content(const struct ich_desc_con * only valid value since. Skylake is currently the most important dis- * tinction because of the dropped number of regions field (NR). */ -enum ich_chipset guess_ich_chipset(const struct ich_desc_content *const content, - const struct ich_desc_component *const component) +static enum ich_chipset guess_ich_chipset(const struct ich_desc_content *const content, + const struct ich_desc_component *const component) { const enum ich_chipset guess = guess_ich_chipset_from_content(content); @@ -765,9 +850,10 @@ enum ich_chipset guess_ich_chipset(const struct ich_desc_content *const content, } /* len is the length of dump in bytes */ -int read_ich_descriptors_from_dump(const uint32_t *dump, unsigned int len, struct ich_descriptors *desc) +int read_ich_descriptors_from_dump(const uint32_t *const dump, const size_t len, + enum ich_chipset *const cs, struct ich_descriptors *const desc) { - unsigned int i, max_count; + size_t i, max_count; uint8_t pch_bug_offset = 0; if (dump == NULL || desc == NULL) @@ -795,21 +881,22 @@ int read_ich_descriptors_from_dump(const uint32_t *dump, unsigned int len, struc desc->component.FLILL = dump[(getFCBA(&desc->content) >> 2) + 1]; desc->component.FLPB = dump[(getFCBA(&desc->content) >> 2) + 2]; + if (*cs == CHIPSET_ICH_UNKNOWN) + *cs = guess_ich_chipset(&desc->content, &desc->component); + /* region */ - if (len < getFRBA(&desc->content) + 5 * 4) + const ssize_t nr = ich_number_of_regions(*cs, &desc->content); + if (nr < 0 || len < getFRBA(&desc->content) + nr * 4) return ICH_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]; + for (i = 0; i < nr; i++) + desc->region.FLREGs[i] = dump[(getFRBA(&desc->content) >> 2) + i]; /* master */ - if (len < getFMBA(&desc->content) + 3 * 4) + const ssize_t nm = ich_number_of_masters(*cs, &desc->content); + if (nm < 0 || len < getFMBA(&desc->content) + nm * 4) return ICH_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]; + for (i = 0; i < nm; i++) + desc->master.FLMSTRs[i] = dump[(getFMBA(&desc->content) >> 2) + i]; /* upper map */ desc->upper.FLUMAP1 = dump[(UPPER_MAP_OFFSET >> 2) + 0]; @@ -929,8 +1016,7 @@ static uint32_t read_descriptor_reg(enum ich_chipset cs, uint8_t section, uint16 int read_ich_descriptors_via_fdo(enum ich_chipset cs, void *spibar, struct ich_descriptors *desc) { - uint8_t i; - uint8_t nr; + size_t i; struct ich_desc_region *r = &desc->region; /* Test if bit-fields are working as expected. @@ -938,20 +1024,20 @@ int read_ich_descriptors_via_fdo(enum ich_chipset cs, void *spibar, struct ich_d */ for (i = 0; i < 4; i++) desc->region.FLREGs[i] = 0x5A << (i * 8); - if (r->reg0_base != 0x005A || r->reg0_limit != 0x0000 || - r->reg1_base != 0x1A00 || r->reg1_limit != 0x0000 || - r->reg2_base != 0x0000 || r->reg2_limit != 0x005A || - r->reg3_base != 0x0000 || r->reg3_limit != 0x1A00) { + if (r->old_reg[0].base != 0x005A || r->old_reg[0].limit != 0x0000 || + r->old_reg[1].base != 0x1A00 || r->old_reg[1].limit != 0x0000 || + r->old_reg[2].base != 0x0000 || r->old_reg[2].limit != 0x005A || + r->old_reg[3].base != 0x0000 || r->old_reg[3].limit != 0x1A00) { msg_pdbg("The combination of compiler and CPU architecture used" "does not lay out bit-fields as expected, sorry.\n"); - msg_pspew("r->reg0_base = 0x%04X (0x005A)\n", r->reg0_base); - msg_pspew("r->reg0_limit = 0x%04X (0x0000)\n", r->reg0_limit); - msg_pspew("r->reg1_base = 0x%04X (0x1A00)\n", r->reg1_base); - msg_pspew("r->reg1_limit = 0x%04X (0x0000)\n", r->reg1_limit); - msg_pspew("r->reg2_base = 0x%04X (0x0000)\n", r->reg2_base); - msg_pspew("r->reg2_limit = 0x%04X (0x005A)\n", r->reg2_limit); - msg_pspew("r->reg3_base = 0x%04X (0x0000)\n", r->reg3_base); - msg_pspew("r->reg3_limit = 0x%04X (0x1A00)\n", r->reg3_limit); + msg_pspew("r->old_reg[0].base = 0x%04X (0x005A)\n", r->old_reg[0].base); + msg_pspew("r->old_reg[0].limit = 0x%04X (0x0000)\n", r->old_reg[0].limit); + msg_pspew("r->old_reg[1].base = 0x%04X (0x1A00)\n", r->old_reg[1].base); + msg_pspew("r->old_reg[1].limit = 0x%04X (0x0000)\n", r->old_reg[1].limit); + msg_pspew("r->old_reg[2].base = 0x%04X (0x0000)\n", r->old_reg[2].base); + msg_pspew("r->old_reg[2].limit = 0x%04X (0x005A)\n", r->old_reg[2].limit); + msg_pspew("r->old_reg[3].base = 0x%04X (0x0000)\n", r->old_reg[3].base); + msg_pspew("r->old_reg[3].limit = 0x%04X (0x1A00)\n", r->old_reg[3].limit); return ICH_RET_ERR; } @@ -968,19 +1054,24 @@ int read_ich_descriptors_via_fdo(enum ich_chipset cs, void *spibar, struct ich_d desc->component.FLPB = read_descriptor_reg(cs, 1, 2, spibar); /* region section */ - nr = desc->content.NR + 1; - if (nr > 5) { + const ssize_t nr = ich_number_of_regions(cs, &desc->content); + if (nr < 0) { msg_pdbg2("%s: number of regions too high (%d) - failed\n", - __func__, nr); + __func__, desc->content.NR + 1); return ICH_RET_ERR; } - for (i = 0; i < 5; i++) + for (i = 0; i < nr; i++) desc->region.FLREGs[i] = read_descriptor_reg(cs, 2, i, spibar); /* master section */ - desc->master.FLMSTR1 = read_descriptor_reg(cs, 3, 0, spibar); - desc->master.FLMSTR2 = read_descriptor_reg(cs, 3, 1, spibar); - desc->master.FLMSTR3 = read_descriptor_reg(cs, 3, 2, spibar); + const ssize_t nm = ich_number_of_masters(cs, &desc->content); + if (nm < 0) { + msg_pdbg2("%s: number of masters too high (%d) - failed\n", + __func__, desc->content.NM + 1); + return ICH_RET_ERR; + } + for (i = 0; i < nm; i++) + desc->master.FLMSTRs[i] = read_descriptor_reg(cs, 3, i, spibar); /* Accessing the strap section via FDOC/D is only possible on ICH8 and * reading the upper map is impossible on all chipsets, so don't bother. @@ -1003,16 +1094,19 @@ int read_ich_descriptors_via_fdo(enum ich_chipset cs, void *spibar, struct ich_d */ int layout_from_ich_descriptors(struct ich_layout *const layout, const void *const dump, const size_t len) { - static const char *regions[] = { "fd", "bios", "me", "gbe", "pd" }; + static const char *const regions[] = { + "fd", "bios", "me", "gbe", "pd", "reg5", "reg6", "reg7", "ec", "reg9" + }; struct ich_descriptors desc; - if (read_ich_descriptors_from_dump(dump, len, &desc)) + enum ich_chipset cs = CHIPSET_ICH_UNKNOWN; + if (read_ich_descriptors_from_dump(dump, len, &cs, &desc)) return 1; memset(layout, 0x00, sizeof(*layout)); - size_t i, j; - for (i = 0, j = 0; i < min(desc.content.NR + 1, ARRAY_SIZE(regions)); ++i) { + ssize_t i, j; + for (i = 0, j = 0; i < min(ich_number_of_regions(cs, &desc.content), ARRAY_SIZE(regions)); ++i) { const chipoff_t base = ICH_FREG_BASE(desc.region.FLREGs[i]); const chipoff_t limit = ICH_FREG_LIMIT(desc.region.FLREGs[i]); if (limit <= base) diff --git a/ich_descriptors.h b/ich_descriptors.h index 920e098c9..bccea2776 100644 --- a/ich_descriptors.h +++ b/ich_descriptors.h @@ -62,8 +62,8 @@ #define VSCC_VCL (0x1 << VSCC_VCL_OFF) /* 24-31: reserved */ -#define ICH_FREG_BASE(flreg) (((flreg) << 12) & 0x01fff000) -#define ICH_FREG_LIMIT(flreg) ((((flreg) >> 4) & 0x01fff000) | 0x00000fff) +#define ICH_FREG_BASE(flreg) (((flreg) << 12) & 0x07fff000) +#define ICH_FREG_LIMIT(flreg) ((((flreg) >> 4) & 0x07fff000) | 0x00000fff) void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity, bool print_vcl); @@ -76,7 +76,7 @@ struct ich_desc_content { NC :2, /* Number Of Components */ :6, FRBA :8, /* Flash Region Base Address */ - NR :3, /* Number Of Regions */ + NR :3, /* Number Of Regions (reserved from Skylake on) */ :5; }; }; @@ -116,7 +116,8 @@ struct ich_desc_component { * Patsburg: 50 30 5 0:2, 3:5 * Panther Point/7 50 30 5 0:2, 3:5 * Lynx Point/8: 50 30 7 0:3, 4:7 - * Wildcat Point/9: 50 ?? (multi I/O) ? ?:?, ?:? + * Wildcat Point/9: 50 30 (multi I/O) 7 0:3, 4:7 + * Sunrise Point/100: 48 30 7 0:3, 4:7 */ struct { uint32_t :17, @@ -149,55 +150,49 @@ struct ich_desc_component { }; }; union { /* 0x08 */ - uint32_t FLPB; /* Flash Partition Boundary Register */ + uint32_t FLPB; /* Flash Partition Boundary Register, until Panther Point/7 */ struct { uint32_t FPBA :13, /* Flash Partition Boundary Addr */ :19; }; - }; -}; - -struct ich_desc_region { - union { - uint32_t FLREGs[5]; + uint32_t FLILL1; /* Flash Invalid Instructions Register, new since Sunrise Point/100 */ struct { - struct { /* FLREG0 Flash Descriptor */ - uint32_t reg0_base :13, - :3, - reg0_limit :13, - :3; - }; - struct { /* FLREG1 BIOS */ - uint32_t reg1_base :13, - :3, - reg1_limit :13, - :3; - }; - struct { /* FLREG2 ME */ - uint32_t reg2_base :13, - :3, - reg2_limit :13, - :3; - }; - struct { /* FLREG3 GbE */ - uint32_t reg3_base :13, - :3, - reg3_limit :13, - :3; - }; - struct { /* FLREG4 Platform */ - uint32_t reg4_base :13, - :3, - reg4_limit :13, - :3; - }; + uint32_t invalid_instr4 :8, + invalid_instr5 :8, + invalid_instr6 :8, + invalid_instr7 :8; }; }; }; +#define MAX_NUM_FLREGS 10 /* 16 on unsupported Lewisburg PCH */ +struct ich_desc_region { + /* + * Number of entries and width differ on various generations: + * + * Chipset/Generation #FLREGs width (bits) + * ICH8 .. Panther Point/7 5 13 + * Lynx Point/8 .. Wildcat Point/9 7 15 + * Sunrise Point/100 .. 10 15 + */ + union { + uint32_t FLREGs[MAX_NUM_FLREGS]; /* Flash Descriptor Regions */ + + /* only used for bit-field check */ + struct { + uint32_t base :13, + :3, + limit :13, + :3; + } old_reg[MAX_NUM_FLREGS]; + }; +}; + +#define MAX_NUM_MASTERS 5 /* 6 on unsupported Lewisburg PCH */ struct ich_desc_master { union { - uint32_t FLMSTR1; + uint32_t FLMSTRs[MAX_NUM_MASTERS]; /* Flash Masters */ + /* For pre-Skylake platforms */ struct { uint32_t BIOS_req_ID :16, BIOS_descr_r :1, @@ -212,11 +207,6 @@ struct ich_desc_master { BIOS_GbE_w :1, BIOS_plat_w :1, :3; - }; - }; - union { - uint32_t FLMSTR2; - struct { uint32_t ME_req_ID :16, ME_descr_r :1, ME_BIOS_r :1, @@ -230,11 +220,6 @@ struct ich_desc_master { ME_GbE_w :1, ME_plat_w :1, :3; - }; - }; - union { - uint32_t FLMSTR3; - struct { uint32_t GbE_req_ID :16, GbE_descr_r :1, GbE_BIOS_r :1, @@ -249,6 +234,12 @@ struct ich_desc_master { GbE_plat_w :1, :3; }; + /* From Skylake on */ + struct { + uint32_t :8, + read :12, + write :12; + } mstr[MAX_NUM_MASTERS]; }; }; @@ -573,16 +564,19 @@ struct ich_descriptors { struct ich_desc_upper_map upper; }; +ssize_t ich_number_of_regions(enum ich_chipset cs, const struct ich_desc_content *content); +ssize_t ich_number_of_masters(enum ich_chipset cs, const struct ich_desc_content *content); + void prettyprint_ich_descriptors(enum ich_chipset cs, const struct ich_descriptors *desc); -void prettyprint_ich_descriptor_content(const struct ich_desc_content *content); +void prettyprint_ich_descriptor_content(enum ich_chipset cs, const struct ich_desc_content *content); void prettyprint_ich_descriptor_component(enum ich_chipset cs, 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); +void prettyprint_ich_descriptor_region(enum ich_chipset cs, const struct ich_descriptors *desc); +void prettyprint_ich_descriptor_master(enum ich_chipset cs, const struct ich_descriptors *desc); 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, struct ich_descriptors *desc); +int read_ich_descriptors_from_dump(const uint32_t *dump, size_t len, enum ich_chipset *cs, struct ich_descriptors *desc); int read_ich_descriptors_via_fdo(enum ich_chipset cs, void *spibar, struct ich_descriptors *desc); int getFCBA_component_density(enum ich_chipset cs, const struct ich_descriptors *desc, uint8_t idx); diff --git a/util/ich_descriptors_tool/ich_descriptors_tool.c b/util/ich_descriptors_tool/ich_descriptors_tool.c index 7dfa5c07e..82c74bd9c 100644 --- a/util/ich_descriptors_tool/ich_descriptors_tool.c +++ b/util/ich_descriptors_tool/ich_descriptors_tool.c @@ -40,15 +40,18 @@ #include #endif -static void dump_file(const char *prefix, const uint32_t *dump, unsigned int len, struct ich_desc_region *reg, unsigned int i) +static const char *const region_names[] = { + "Descriptor", "BIOS", "ME", "GbE", "Platform", + "Region5", "Region6", "Region7", "EC", "Region9", +}; + +static void dump_file(const char *prefix, const uint32_t *dump, unsigned int len, + const struct ich_desc_region *const 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]); @@ -94,12 +97,19 @@ static void dump_file(const char *prefix, const uint32_t *dump, unsigned int len close(fh); } -void dump_files(const char *name, const uint32_t *buf, unsigned int len, struct ich_desc_region *reg) +int min(int a, int b) { - unsigned int i; + return (a < b) ? a : b; +} + +static void dump_files(const char *name, const uint32_t *buf, unsigned int len, + const enum ich_chipset cs, const struct ich_descriptors *const desc) +{ + ssize_t i; + const ssize_t nr = min(ich_number_of_regions(cs, &desc->content), ARRAY_SIZE(region_names)); printf("=== Dumping region files ===\n"); - for (i = 0; i < 5; i++) - dump_file(name, buf, len, reg, i); + for (i = 0; i < nr; i++) + dump_file(name, buf, len, &desc->region, i); printf("\n"); } @@ -123,6 +133,7 @@ static void usage(char *argv[], char *error) "\t- \"7\" or \"panther\" for Intel's 7 series chipsets.\n" "\t- \"8\" or \"lynx\" for Intel's 8 series chipsets.\n" "\t- \"9\" or \"wildcat\" for Intel's 9 series chipsets.\n" +"\t- \"100\" or \"sunrise\" for Intel's 100 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]); @@ -208,9 +219,12 @@ int main(int argc, char *argv[]) else if ((strcmp(csn, "9") == 0) || (strcmp(csn, "wildcat") == 0)) cs = CHIPSET_9_SERIES_WILDCAT_POINT; + else if ((strcmp(csn, "100") == 0) || + (strcmp(csn, "sunrise") == 0)) + cs = CHIPSET_100_SERIES_SUNRISE_POINT; } - ret = read_ich_descriptors_from_dump(buf, len, &desc); + ret = read_ich_descriptors_from_dump(buf, len, &cs, &desc); switch (ret) { case ICH_RET_OK: break; @@ -228,15 +242,15 @@ int main(int argc, char *argv[]) prettyprint_ich_descriptors(cs, &desc); - pMAC = (uint8_t *) &buf[ICH_FREG_BASE(desc.region.reg3_base) >> 2]; - if (len >= ICH_FREG_BASE(desc.region.reg3_base) + 6 && pMAC[0] != 0xff) + pMAC = (uint8_t *) &buf[ICH_FREG_BASE(desc.region.FLREGs[3]) >> 2]; + if (len >= ICH_FREG_BASE(desc.region.FLREGs[3]) + 6 && pMAC[0] != 0xff) printf("The MAC address might be at offset 0x%x: " "%02x:%02x:%02x:%02x:%02x:%02x\n", - ICH_FREG_BASE(desc.region.reg3_base), + ICH_FREG_BASE(desc.region.FLREGs[3]), pMAC[0], pMAC[1], pMAC[2], pMAC[3], pMAC[4], pMAC[5]); if (dump == 1) - dump_files(fn, buf, len, &desc.region); + dump_files(fn, buf, len, cs, &desc); return 0; }