Subrata Banik has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/80235?usp=email )
Change subject: util/ifdtool: Add new cmdline to enable GPR0 protection ......................................................................
util/ifdtool: Add new cmdline to enable GPR0 protection
This patch adds new cmdline `-E` support in the IFD Tool so that users (mostly factory) can enable GPR0 protection. Additionally, perform some code refactoring while adding support for enable GPR0 protection.
BUG=b:270275115 TEST=Able to test GPR0 protection on google/rex and google/yahiko.
ifdtool -p mtl -E image.bin -O image.bin_lock
--------- GPR0 Protected Range -------------- Start address = 0x00004000 End address = 0x00322fff
Change-Id: I27c533ae4109c79299f4e7ff75e750d7cc64280f Signed-off-by: Subrata Banik subratabanik@google.com --- M util/ifdtool/ifdtool.c M util/ifdtool/ifdtool.h 2 files changed, 187 insertions(+), 15 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/35/80235/1
diff --git a/util/ifdtool/ifdtool.c b/util/ifdtool/ifdtool.c index 07cc268..0b9bef0 100644 --- a/util/ifdtool/ifdtool.c +++ b/util/ifdtool/ifdtool.c @@ -44,6 +44,8 @@ #define PLATFORM_HAS_10GBE_0_REGION (platform == PLATFORM_DNV) #define PLATFORM_HAS_10GBE_1_REGION (platform == PLATFORM_DNV)
+#define CSE_REGION_DATA_PARTITION_OFFSET 0x18 + static int max_regions_from_fdbar(const struct fdbar *fdb);
static int ifd_version; @@ -1551,14 +1553,26 @@ write_image(filename, image, size); }
-static void disable_gpr0(const char *filename, char *image, int size) +static void print_gpr0_range(uint32_t gprd) { - struct fpsba *fpsba = find_fpsba(image, size); - if (!fpsba) - exit(EXIT_FAILURE); + printf("--------- GPR0 Protected Range --------------\n"); + /* + * Start Address: bit 0-15 of the GPRD represents the protected region start address, + * where bit 0-11 of the start address are assumed to be zero. + */ + printf("Start address = 0x%08x\n", (gprd & 0xffff) << 12); + /* + * End Address: bit 16-30 of the GPRD represents the protected region end address, + * where bit 0-11 of the end address are assumed to be 0xfff. + */ + printf("End address = 0x%08x\n", ((gprd >> 16) & 0x7fff) << 12 | 0xfff); +}
+static uint32_t get_gpr0_offset(void) +{ /* Offset expressed as number of 32-bit fields from FPSBA */ - uint32_t gpr0_offset; + uint32_t gpr0_offset = 0xffffffff; + switch (platform) { case PLATFORM_CNL: gpr0_offset = 0x10; @@ -1574,9 +1588,24 @@ gpr0_offset = 0x40; break; default: + break; + } + + return gpr0_offset; +} + +static void disable_gpr0(const char *filename, char *image, int size) +{ + struct fpsba *fpsba = find_fpsba(image, size); + if (!fpsba) + exit(EXIT_FAILURE); + + uint32_t gpr0_offset = get_gpr0_offset(); + if (gpr0_offset == 0xffffffff) { fprintf(stderr, "Disabling GPR0 not supported on this platform\n"); exit(EXIT_FAILURE); } + /* If bit 31 is set then GPR0 protection is enable */ bool gpr0_status = fpsba->pchstrp[gpr0_offset] & 0x80000000; if (!gpr0_status) { @@ -1585,20 +1614,136 @@ }
printf("Value at GPRD offset (%d) is 0x%08x\n", gpr0_offset, fpsba->pchstrp[gpr0_offset]); - printf("--------- GPR0 Protected Range --------------\n"); + print_gpr0_range(fpsba->pchstrp[gpr0_offset]); + /* 0 means GPR0 protection is disabled */ + fpsba->pchstrp[gpr0_offset] = 0; + write_image(filename, image, size); +} + +/* + * Helper function to parse the FITC to retrieve the FIT start offset and size. + * FITC is a sub-partition table inside CSE data partition known as FPT. + * + * CSE Region + * |-----> CSE Data Partition Offset + * | |-------> FPT Entry + * | | |-> Sub Partition 1 + * | | |-> Sub Partition 2 + * | | |-> FITC + * | | | | -> FITC Offset + * | | | | -> FITC Length + */ +static void parse_fitc_table(struct cse_fpt *fpt, uint32_t *offset, + size_t *size) +{ + for (size_t index = 1; index <= fpt->count; index++) { + struct cse_fpt_sub_part *fpt_sub_part = (struct cse_fpt_sub_part *)(fpt + index); + if (!strncmp(&fpt_sub_part->signature[0], "FITC", 4)) { + *offset = fpt_sub_part->offset; + *size = fpt_sub_part->length; + return; + } + continue; + } +} + +/* + * Formula to calculate the GPR0 protection range as below: + * Start: CSE Region Base Offset + * End: Till the end of FITC sub-partition + */ +static int calculate_gpr0_range(char *image, int size, + uint32_t *gpr0_start, uint32_t *gpr0_end) +{ + struct frba *frba = find_frba(image, size); + if (!frba) + return -1; + + struct region region = get_region(frba, REGION_ME); + if (region.size <= 0xfff) { + fprintf(stderr, "Region %s is disabled in target\n", + region_name(REGION_ME)); + return -1; + } + + /* CSE Region Start */ + uint32_t cse_region_start = region.base; + /* CSE Data Partition Offset (at 0x18 offset of CSE region) */ + uint32_t data_part_offset = *((uint32_t *)(image + cse_region_start + + CSE_REGION_DATA_PARTITION_OFFSET)); + /* Start reading the CSE Data Partition Table, also known as FPT */ + uint32_t data_part_start = data_part_offset + cse_region_start; + + uint32_t fitc_region_start; + size_t fitc_region_size; + /* + * FPT holds entry for own FPT data structure also bunch of sub-partitions. + * `FITC` is one of such sub-partition entry. + */ + parse_fitc_table(((struct cse_fpt *)(image + data_part_start)), + &fitc_region_start, &fitc_region_size); + + /* + * GPR0 protection is configured to the following range: + * start: CSE region base offset + * end: Till the end of FITC sub-partition (i.e. CSE region + data partition offset + + * FITC sub partition offset + FITC sub partition size) + */ + *gpr0_start = cse_region_start; + *gpr0_end = (cse_region_start + data_part_offset + + fitc_region_start + fitc_region_size) - 1; + + return 0; +} + +static void enable_gpr0(const char *filename, char *image, int size) +{ + struct fpsba *fpsba = find_fpsba(image, size); + if (!fpsba) + exit(EXIT_FAILURE); + + uint32_t gpr0_offset = get_gpr0_offset(); + if (gpr0_offset == 0xffffffff) { + fprintf(stderr, "Enabling GPR0 not supported on this platform\n"); + exit(EXIT_FAILURE); + } + + /* If bit 31 is set then GPR0 protection is enable */ + bool gpr0_status = fpsba->pchstrp[gpr0_offset] & 0x80000000; + if (gpr0_status) { + printf("GPR0 protection is already enabled\n"); + print_gpr0_range(fpsba->pchstrp[gpr0_offset]); + return; + } + + uint32_t gpr0_range_start, gpr0_range_end; + + if (calculate_gpr0_range(image, size, &gpr0_range_start, &gpr0_range_end)) + exit(EXIT_FAILURE); + + union gprd_info { + struct bit_field { + uint32_t start:16; + uint32_t end:15; + uint32_t enable:1; + } data; + uint32_t value; + } gprd; + /* * Start Address: bit 0-15 of the GPRD represents the protected region start address, * where bit 0-11 of the start address are assumed to be zero. */ - printf("Start address = 0x%08x\n", (fpsba->pchstrp[gpr0_offset] & 0xffff) << 12); + gprd.data.start = (gpr0_range_start >> 12) & 0xffff; /* * End Address: bit 16-30 of the GPRD represents the protected region end address, * where bit 0-11 of the end address are assumed to be 0xfff. */ - printf("End address = 0x%08x\n", - ((fpsba->pchstrp[gpr0_offset] >> 16) & 0x7fff) << 12 | 0xfff); - /* 0 means GPR0 protection is disabled */ - fpsba->pchstrp[gpr0_offset] = 0; + gprd.data.end = (gpr0_range_end >> 12) & 0x7fff; + gprd.data.enable = 1; + + fpsba->pchstrp[gpr0_offset] = gprd.value; + print_gpr0_range(gprd.value); write_image(filename, image, size); }
@@ -1942,6 +2087,7 @@ " -r | --read Enable CPU/BIOS read access for ME region\n" " -u | --unlock Unlock firmware descriptor and ME region\n" " -g | --gpr0-disable Disable GPR0 (Global Protected Range) register\n" + " -E | --gpr0-enable Enable GPR0 (Global Protected Range) register\n" " -M | --altmedisable <0|1> Set the MeDisable and AltMeDisable (or HAP for skylake or newer platform)\n" " bits to disable ME\n" " -p | --platform Add platform-specific quirks\n" @@ -1975,7 +2121,7 @@ int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0, mode_validate = 0; 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; + int mode_gpr0_disable = 0, mode_gpr0_enable = 0;; char *region_type_string = NULL, *region_fname = NULL; const char *layout_fname = NULL; char *new_filename = NULL; @@ -2002,6 +2148,7 @@ {"read", 0, NULL, 'r'}, {"unlock", 0, NULL, 'u'}, {"gpr0-disable", 0, NULL, 'g'}, + {"gpr0-enable", 0, NULL, 'E'}, {"version", 0, NULL, 'v'}, {"help", 0, NULL, 'h'}, {"platform", 0, NULL, 'p'}, @@ -2011,7 +2158,7 @@ {0, 0, 0, 0} };
- while ((opt = getopt_long(argc, argv, "S:V:df:F:D:C:M:xi:n:O:s:p:elrugvth?", + while ((opt = getopt_long(argc, argv, "S:V:df:F:D:C:M:xi:n:O:s:p:elrugEvth?", long_options, &option_index)) != EOF) { switch (opt) { case 'd': @@ -2217,6 +2364,9 @@ case 'g': mode_gpr0_disable = 1; break; + case 'E': + mode_gpr0_enable = 1; + break; case 'p': if (!strcmp(optarg, "aplk")) { platform = PLATFORM_APL; @@ -2270,7 +2420,7 @@ if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject + mode_setstrap + mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked | mode_locked) + mode_altmedisable + mode_validate + - mode_gpr0_disable) > 1) { + (mode_gpr0_disable | mode_gpr0_enable)) > 1) { fprintf(stderr, "You may not specify more than one mode.\n\n"); fprintf(stderr, "run '%s -h' for usage\n", argv[0]); exit(EXIT_FAILURE); @@ -2279,7 +2429,7 @@ if ((mode_dump + mode_layout + mode_fmap_template + mode_extract + mode_inject + mode_setstrap + mode_newlayout + mode_spifreq + mode_em100 + mode_locked + mode_unlocked + mode_density + mode_altmedisable + - mode_validate + mode_gpr0_disable) == 0) { + mode_validate + (mode_gpr0_disable | mode_gpr0_enable)) == 0) { fprintf(stderr, "You need to specify a mode.\n\n"); fprintf(stderr, "run '%s -h' for usage\n", argv[0]); exit(EXIT_FAILURE); @@ -2379,6 +2529,9 @@ if (mode_gpr0_disable) disable_gpr0(new_filename, image, size);
+ if (mode_gpr0_enable) + enable_gpr0(new_filename, image, size); + if (mode_setstrap) { struct fpsba *fpsba = find_fpsba(image, size); const struct fdbar *fdb = find_fd(image, size); diff --git a/util/ifdtool/ifdtool.h b/util/ifdtool/ifdtool.h index 219634b..79fe0ab 100644 --- a/util/ifdtool/ifdtool.h +++ b/util/ifdtool/ifdtool.h @@ -208,3 +208,22 @@ const char *filename; const char *fmapname; }; + +struct cse_fpt { + const char signature[4]; + uint32_t count; + uint8_t header_version; + uint8_t entry_version; + uint8_t length; + uint8_t crc; + uint8_t reserved[20]; +}; + +struct cse_fpt_sub_part { + const char signature[4]; + uint32_t reserved_1; + uint32_t offset; + uint32_t length; + uint8_t reserved_2[12]; + uint32_t flags; +};