summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;
+};