summaryrefslogtreecommitdiff
path: root/util/ifdtool
diff options
context:
space:
mode:
authorSubrata Banik <subratabanik@google.com>2024-01-30 00:31:08 +0530
committerSubrata Banik <subratabanik@google.com>2024-02-02 05:18:32 +0000
commit5fe229744d48dc84af572d6f657ecefb51c1b396 (patch)
tree892842b8aff7c6771aa59b392a26fa2f860f3cbe /util/ifdtool
parentd5bcfe157513beb45fcd18d5f6fb08f7412310e3 (diff)
util/ifdtool: Add a new switch -E to protect GPR0
This patch adds support for the new command-line option `-E` to the ifdtool, which enables users (primarily factory users) to protect GPR0. Additionally, this patch refactors some code while adding support for enabling GPR0 protection. For more information on the scope of GPR0 (General Protection Range 0), please refer to the Intel Meteor Lake-U Type 4 Client Platform SPI Programming Guide, Document Number 768150. 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 ... Value at GPRD offset (64) is 0x83220004 --------- GPR0 Protected Range -------------- Start address = 0x00004000 End address = 0x00322fff ... GPR0 protection is now enabled Change-Id: I27c533ae4109c79299f4e7ff75e750d7cc64280f Signed-off-by: Subrata Banik <subratabanik@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/80235 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Paul Menzel <paulepanter@mailbox.org> Reviewed-by: Reka Norman <rekanorman@chromium.org>
Diffstat (limited to 'util/ifdtool')
-rw-r--r--util/ifdtool/ifdtool.c234
-rw-r--r--util/ifdtool/ifdtool.h19
2 files changed, 231 insertions, 22 deletions
diff --git a/util/ifdtool/ifdtool.c b/util/ifdtool/ifdtool.c
index 07cc26823b..e020a8ae07 100644
--- a/util/ifdtool/ifdtool.c
+++ b/util/ifdtool/ifdtool.c
@@ -44,6 +44,32 @@
#define PLATFORM_HAS_10GBE_0_REGION (platform == PLATFORM_DNV)
#define PLATFORM_HAS_10GBE_1_REGION (platform == PLATFORM_DNV)
+union gprd {
+ struct bit_field {
+ /*
+ * Start Address: bit 0-14 of the GPRD represents the
+ * protected region start address, where bit 0-11 of
+ * the start address are assumed to be zero.
+ */
+ uint32_t start:15;
+
+ /* Specifies read protection is enabled */
+ uint32_t read_protect_en:1;
+
+ /*
+ * 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.
+ */
+ uint32_t end:15;
+
+ /* Specifies write protection is enabled */
+ uint32_t write_protect_en:1;
+ } __packed data;
+
+ uint32_t value;
+};
+
static int max_regions_from_fdbar(const struct fdbar *fdb);
static int ifd_version;
@@ -1551,14 +1577,39 @@ static void unlock_descriptor(const char *filename, char *image, int size)
write_image(filename, image, size);
}
-static void disable_gpr0(const char *filename, char *image, int size)
+static void print_gpr0_range(union gprd reg)
{
- struct fpsba *fpsba = find_fpsba(image, size);
- if (!fpsba)
- exit(EXIT_FAILURE);
+ printf("--------- GPR0 Protected Range --------------\n");
+ printf("Start address = 0x%08x\n", reg.data.start << 12);
+ printf("End address = 0x%08x\n", (reg.data.end << 12) | 0xfff);
+}
+
+static uint8_t get_cse_data_partition_offset(void)
+{
+ uint8_t data_offset = 0xff;
+
+ switch (platform) {
+ case PLATFORM_CNL:
+ case PLATFORM_JSL:
+ data_offset = 0x10;
+ break;
+ case PLATFORM_TGL:
+ case PLATFORM_ADL:
+ case PLATFORM_MTL:
+ data_offset = 0x18;
+ break;
+ default:
+ break;
+ }
+
+ return data_offset;
+}
+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,32 +1625,163 @@ static void disable_gpr0(const char *filename, char *image, int size)
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);
}
+
+ union gprd reg;
/* If bit 31 is set then GPR0 protection is enable */
- bool gpr0_status = fpsba->pchstrp[gpr0_offset] & 0x80000000;
- if (!gpr0_status) {
+ reg.value = fpsba->pchstrp[gpr0_offset];
+ if (!reg.data.write_protect_en) {
printf("GPR0 protection is already disabled\n");
return;
}
- printf("Value at GPRD offset (%d) is 0x%08x\n", gpr0_offset, fpsba->pchstrp[gpr0_offset]);
- printf("--------- GPR0 Protected Range --------------\n");
+ printf("Value at GPRD offset (%d) is 0x%08x\n", gpr0_offset, reg.value);
+ print_gpr0_range(reg);
+ /* 0 means GPR0 protection is disabled */
+ fpsba->pchstrp[gpr0_offset] = 0;
+ write_image(filename, image, size);
+ printf("GPR0 protection is now disabled\n");
+}
+
+/*
+ * Helper function to parse the FPT to retrieve the FITC 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 int parse_fitc_table(struct cse_fpt *fpt, uint32_t *offset,
+ size_t *size)
+{
+ size_t num_part_header = fpt->count;
+ /* Move to the next structure which is FPT sub-partition entries */
+ struct cse_fpt_sub_part *fpt_sub_part = (struct cse_fpt_sub_part *)(fpt + 1);
+ for (size_t index = 0; index < num_part_header; index++) {
+ if (!strncmp(fpt_sub_part->signature, "FITC", 4)) {
+ *offset = fpt_sub_part->offset;
+ *size = fpt_sub_part->length;
+ return 0;
+ }
+ fpt_sub_part++;
+ }
+
+ return -1;
+}
+
+/*
+ * 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 <= 0) {
+ 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;
+ /* Get CSE Data Partition Offset */
+ uint8_t cse_data_offset = get_cse_data_partition_offset();
+ if (cse_data_offset == 0xff) {
+ fprintf(stderr, "Unsupported platform\n");
+ exit(EXIT_FAILURE);
+ }
+ uint32_t data_part_offset = *((uint32_t *)(image + cse_region_start + cse_data_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 = 0;
+ size_t fitc_region_size = 0;
/*
- * 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.
+ * FPT holds entry for own FPT data structure also bunch of sub-partitions.
+ * `FITC` is one of such sub-partition entry.
*/
- printf("Start address = 0x%08x\n", (fpsba->pchstrp[gpr0_offset] & 0xffff) << 12);
+ if (parse_fitc_table(((struct cse_fpt *)(image + data_part_start)),
+ &fitc_region_start, &fitc_region_size) < 0) {
+ fprintf(stderr, "Unable to find FITC entry\n");
+ return -1;
+ }
+
/*
- * 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.
+ * 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)
*/
- 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;
+ *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);
+ }
+
+ union gprd reg;
+ /* If bit 31 is set then GPR0 protection is enable */
+ reg.value = fpsba->pchstrp[gpr0_offset];
+ if (reg.data.write_protect_en) {
+ printf("GPR0 protection is already enabled\n");
+ print_gpr0_range(reg);
+ return;
+ }
+
+ uint32_t gpr0_range_start, gpr0_range_end;
+
+ if (calculate_gpr0_range(image, size, &gpr0_range_start, &gpr0_range_end))
+ exit(EXIT_FAILURE);
+
+ reg.data.start = (gpr0_range_start >> 12) & 0x7fff;
+ reg.data.end = (gpr0_range_end >> 12) & 0x7fff;
+ reg.data.read_protect_en = 0;
+ reg.data.write_protect_en = 1;
+
+ fpsba->pchstrp[gpr0_offset] = reg.value;
+ printf("Value at GPRD offset (%d) is 0x%08x\n", gpr0_offset, reg.value);
+ print_gpr0_range(reg);
write_image(filename, image, size);
+ printf("GPR0 protection is now enabled\n");
}
static void set_pchstrap(struct fpsba *fpsba, const struct fdbar *fdb, const int strap,
@@ -1942,6 +2124,7 @@ static void print_usage(const char *name)
" -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 +2158,7 @@ int main(int argc, char *argv[])
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 +2185,7 @@ int main(int argc, char *argv[])
{"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 +2195,7 @@ int main(int argc, char *argv[])
{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 +2401,9 @@ int main(int argc, char *argv[])
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 +2457,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_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 +2466,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_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 +2566,9 @@ int main(int argc, char *argv[])
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 219634b21d..79fe0abc06 100644
--- a/util/ifdtool/ifdtool.h
+++ b/util/ifdtool/ifdtool.h
@@ -208,3 +208,22 @@ struct region_name {
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;
+};