diff --git a/util/ifdtool/ifdtool.c b/util/ifdtool/ifdtool.c index b21a89c0e1..fc0cb5fa4e 100644 --- a/util/ifdtool/ifdtool.c +++ b/util/ifdtool/ifdtool.c @@ -2173,6 +2173,16 @@ static void new_layout(const char *filename, char *image, int size, free(new_image); } +static uint32_t uint_log2(uint32_t n) +{ + int log = -1; + while (n) { + n >>= 1; + ++log; + } + return log; +} + static void print_version(void) { printf("ifdtool v%s -- ", IFDTOOL_VERSION); @@ -2231,6 +2241,9 @@ static void print_usage(const char *name) " wbg - Wellsburg\n" " -S | --setpchstrap Write a PCH strap\n" " -V | --newvalue The new value to write into PCH strap specified by -S\n" + " -T | --topswapsize Set the Top Swap Block Size PCH strap value\n" + " Possible values: 0x10000, 0x20000, 0x40000, 0x80000,\n" + " 0x100000, 0x200000, 0x400000, 0x800000\n" " -v | --version: print the version\n" " -h | --help: print this help\n\n" " is one of Descriptor, BIOS, ME, GbE, Platform Data, Secondary BIOS, " @@ -2246,8 +2259,9 @@ int main(int argc, char *argv[]) int mode_layout = 0, mode_newlayout = 0, mode_density = 0, mode_setstrap = 0; int mode_read = 0, mode_altmedisable = 0, altmedisable = 0, mode_fmap_template = 0; int mode_gpr0_disable = 0, mode_gpr0_enable = 0, mode_gpr0_status = 0; + int mode_settopswapsize = 0; char *region_type_string = NULL, *region_fname = NULL, *layout_fname = NULL; - char *new_filename = NULL; + char *new_filename = NULL, *top_swap_size_arg = NULL; int region_type = -1, inputfreq = 0; unsigned int value = 0; unsigned int pchstrap = 0; @@ -2279,10 +2293,11 @@ int main(int argc, char *argv[]) {"validate", 0, NULL, 't'}, {"setpchstrap", 1, NULL, 'S'}, {"newvalue", 1, NULL, 'V'}, + {"topswapsize", 1, NULL, 'T'}, {0, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "S:V:df:F:D:C:M:xi:n:O:s:p:elrugEcvth?", + while ((opt = getopt_long(argc, argv, "S:V:df:F:D:C:M:xi:n:O:s:p:T:elrugEcvth?", long_options, &option_index)) != EOF) { switch (opt) { case 'd': @@ -2533,6 +2548,10 @@ int main(int argc, char *argv[]) case 't': mode_validate = 1; break; + case 'T': + mode_settopswapsize = 1; + top_swap_size_arg = optarg; + break; case 'v': print_version(); exit(EXIT_SUCCESS); @@ -2550,7 +2569,7 @@ int main(int argc, char *argv[]) } if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject + - mode_setstrap + mode_newlayout + (mode_spifreq | mode_em100 | + mode_setstrap + mode_settopswapsize + mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked | mode_locked) + mode_altmedisable + mode_validate + (mode_gpr0_disable | mode_gpr0_enable) + mode_gpr0_status) > 1) { fprintf(stderr, "You may not specify more than one mode.\n\n"); @@ -2559,7 +2578,7 @@ int main(int argc, char *argv[]) } if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject + - mode_setstrap + mode_newlayout + mode_spifreq + mode_em100 + + mode_setstrap + mode_settopswapsize + mode_newlayout + mode_spifreq + mode_em100 + mode_locked + mode_unlocked + mode_density + mode_altmedisable + mode_validate + (mode_gpr0_disable | mode_gpr0_enable) + mode_gpr0_status) == 0) { fprintf(stderr, "You need to specify a mode.\n\n"); @@ -2667,6 +2686,59 @@ int main(int argc, char *argv[]) if (mode_gpr0_status) is_gpr0_protected(image, size); + if (mode_settopswapsize) { + if (platform == -1) { + fprintf(stderr, "Error: No platform specified.\n"); + exit(EXIT_FAILURE); + } + struct fpsba *fpsba = find_fpsba(image, size); + uint32_t top_swap_size_offset = 0; + switch (platform) { + case PLATFORM_ADL: + // fixed bits for ADL-P / ADL-N + if (fpsba->pchstrp[0xd0 / 4] == 0x00000300) { + // fixed bits for ADL-P + if (((fpsba->pchstrp[0x7c / 4] >> 1) & 0xff) == 0x18) { + printf("Detected ADL-P flash descriptor\n"); + pchstrap = 0x4C / 4; + top_swap_size_offset = 4; + // fixed bits for ADL-N + } else if (((fpsba->pchstrp[0x7c / 4] >> 1) & 0xff) == 0x51) { + printf("Detected ADL-N flash descriptor\n"); + pchstrap = 0x4C / 4; + top_swap_size_offset = 4; + } + } + break; + default: + break; + } + if (pchstrap == 0) { + fprintf(stderr, "Setting top swap size not supported on selected platform.\n"); + exit(EXIT_FAILURE); + } + + uint32_t top_swap_size = strtoul(top_swap_size_arg, NULL, 0); + if (top_swap_size < 0x10000 || !IS_POWER_OF_2(top_swap_size) || top_swap_size > 0x800000) { + fprintf(stderr, + "Unsupported top swap size: %s\n" + "Supported top swap sizes:\n" + "\t0x10000, 0x20000, 0x40000, 0x80000, 0x100000,\n" + "\t0x200000, 0x400000, 0x800000\n", + top_swap_size_arg); + exit(EXIT_FAILURE); + } + // convert to 0x00-0x07 + top_swap_size = uint_log2(top_swap_size / 0x10000); + const struct fdbar *fdb = find_fd(image, size); + value = fpsba->pchstrp[pchstrap]; + value &= ~(0x7 << top_swap_size_offset); + value |= (top_swap_size << top_swap_size_offset); + + set_pchstrap(fpsba, fdb, pchstrap, value); + write_image(new_filename, image, size); + } + if (mode_setstrap) { struct fpsba *fpsba = find_fpsba(image, size); const struct fdbar *fdb = find_fd(image, size);