util/ifdtool: Add support for disabling GPR0

On ChromeOS devices with updateable CSE firmware, the GPR0 (Global
Protected Range) register is used to ensure the CSE RO is write
protected even when the FLMSTR-based protection is temporarily disabled
by coreboot to allow updating the CSE RW. For more details see
Documentation/soc/intel/cse_fw_update/cse_fw_update.md

Therefore to allow modifying the CSE firmware from the CPU, the
descriptor must have both the FLMSTR-based protection disabled (which
can be done using ifdtool --unlock), and GPR0 disabled.

Add an ifdtool option for disabling GPR0. For now I've added support for
all platforms for which I have the SPI programming guide. Support for
more platforms can be added in the future if needed.

BUG=b:270275115
TEST=Run `ifdtool -p adl -g image.bin -O image-unlocked.bin` on a locked
craask image, check the GPR0 field is set to 0.

Change-Id: Iee13ce0b702b3c7a443501cb4fc282580869d03a
Signed-off-by: Reka Norman <rekanorman@chromium.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/79788
Reviewed-by: Subrata Banik <subratabanik@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Reka Norman 2023-10-03 09:47:01 +11:00 committed by Subrata Banik
parent 0f910e7db9
commit c64be928de
1 changed files with 47 additions and 3 deletions

View File

@ -1497,6 +1497,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)
{
struct fpsba *fpsba = find_fpsba(image, size);
if (!fpsba)
exit(EXIT_FAILURE);
/* Offset expressed as number of 32-bit fields from FPSBA */
uint32_t gpr0_offset;
switch (platform) {
case PLATFORM_CNL:
gpr0_offset = 0x10;
break;
case PLATFORM_JSL:
gpr0_offset = 0x12;
break;
case PLATFORM_TGL:
case PLATFORM_ADL:
gpr0_offset = 0x15;
break;
case PLATFORM_MTL:
gpr0_offset = 0x40;
break;
default:
fprintf(stderr, "Disabling GPR0 not supported on this platform\n");
exit(EXIT_FAILURE);
}
/* 0 means GPR0 protection is disabled */
fpsba->pchstrp[gpr0_offset] = 0;
write_image(filename, image, size);
}
static void set_pchstrap(struct fpsba *fpsba, const struct fdbar *fdb, const int strap,
const unsigned int value)
{
@ -1836,6 +1869,7 @@ static void print_usage(const char *name)
" -l | --lock Lock firmware descriptor and ME region\n"
" -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"
" -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"
@ -1869,6 +1903,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;
char *region_type_string = NULL, *region_fname = NULL;
const char *layout_fname = NULL;
char *new_filename = NULL;
@ -1894,6 +1929,7 @@ int main(int argc, char *argv[])
{"lock", 0, NULL, 'l'},
{"read", 0, NULL, 'r'},
{"unlock", 0, NULL, 'u'},
{"gpr0-disable", 0, NULL, 'g'},
{"version", 0, NULL, 'v'},
{"help", 0, NULL, 'h'},
{"platform", 0, NULL, 'p'},
@ -1903,7 +1939,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:elruvth?",
while ((opt = getopt_long(argc, argv, "S:V:df:F:D:C:M:xi:n:O:s:p:elrugvth?",
long_options, &option_index)) != EOF) {
switch (opt) {
case 'd':
@ -2106,6 +2142,9 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
break;
case 'g':
mode_gpr0_disable = 1;
break;
case 'p':
if (!strcmp(optarg, "aplk")) {
platform = PLATFORM_APL;
@ -2158,7 +2197,8 @@ 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) > 1) {
mode_unlocked | mode_locked) + mode_altmedisable + mode_validate +
mode_gpr0_disable) > 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);
@ -2166,7 +2206,8 @@ 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) == 0) {
mode_locked + mode_unlocked + mode_density + mode_altmedisable +
mode_validate + mode_gpr0_disable) == 0) {
fprintf(stderr, "You need to specify a mode.\n\n");
fprintf(stderr, "run '%s -h' for usage\n", argv[0]);
exit(EXIT_FAILURE);
@ -2263,6 +2304,9 @@ int main(int argc, char *argv[])
if (mode_unlocked)
unlock_descriptor(new_filename, image, size);
if (mode_gpr0_disable)
disable_gpr0(new_filename, image, size);
if (mode_setstrap) {
struct fpsba *fpsba = find_fpsba(image, size);
const struct fdbar *fdb = find_fd(image, size);