ifdtool: Update to support Skylake+ descriptor format

The descriptor format has changed with Skylake and some fields have
moved or been expanded.

This includes new SPI frequencies and chip densities, though unfortunately
30MHz in the new format conflicts with 50MHz in the old format...

There are also new regions with a few reserved regions inserted before
a new embedded controller region.

Unfortunately there does not seem to be a documented version field
so there does not seem to be an official way to determine if a
specific descriptor is new or old.  To work around this ifdtool
checks the hardcoded "SPI Read Frequency" to see if it set for
20MHz (old descriptor) or 17MHz (new descriptor).

BUG=chrome-os-partner:40635
BUG=chrome-os-partner:43461
BRANCH=none
TEST=run ifdtool on skylake and broadwell images

Original-Change-Id: I0561b3c65fcb3e77c0a24be58b01db9b3a36e5a9
Original-Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/281001
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Original-Commit-Queue: Aaron Durbin <adurbin@chromium.org>

Change-Id: I9a08c26432e13c4000afc50de9d8473e6f911805
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/293240
Reviewed-on: http://review.coreboot.org/11228
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
Duncan Laurie 2015-06-22 11:14:48 -07:00 committed by Aaron Durbin
parent e0334e8296
commit 1f7fd720c8
2 changed files with 201 additions and 44 deletions

View File

@ -31,14 +31,18 @@
#define O_BINARY 0
#endif
#define NUM_REGIONS 5
static int ifd_version;
static const struct region_name region_names[NUM_REGIONS] = {
static const struct region_name region_names[MAX_REGIONS] = {
{ "Flash Descriptor", "fd" },
{ "BIOS", "bios" },
{ "Intel ME", "me" },
{ "GbE", "gbe" },
{ "Platform Data", "pd" }
{ "Platform Data", "pd" },
{ "Reserved", "res1" },
{ "Reserved", "res2" },
{ "Reserved", "res3" },
{ "EC" "ec" },
};
static fdbar_t *find_fd(char *image, int size)
@ -58,11 +62,43 @@ static fdbar_t *find_fd(char *image, int size)
return NULL;
}
printf("Found Flash Descriptor signature at 0x%08x\n", i);
return (fdbar_t *) (image + i);
}
/*
* There is no version field in the descriptor so to determine
* if this is a new descriptor format we check the hardcoded SPI
* read frequency to see if it is fixed at 20MHz or 17MHz.
*/
static void check_ifd_version(char *image, int size)
{
fdbar_t *fdb = find_fd(image, size);
fcba_t *fcba;
int read_freq;
if (!fdb)
exit(EXIT_FAILURE);
fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
if (!fcba)
exit(EXIT_FAILURE);
read_freq = (fcba->flcomp >> 17) & 7;
switch (read_freq) {
case SPI_FREQUENCY_20MHZ:
ifd_version = IFD_VERSION_1;
break;
case SPI_FREQUENCY_17MHZ:
ifd_version = IFD_VERSION_2;
break;
default:
fprintf(stderr, "Unknown descriptor version: %d\n",
read_freq);
exit(EXIT_FAILURE);
}
}
static region_t get_region(frba_t *frba, int region_type)
{
region_t region;
@ -89,8 +125,24 @@ static region_t get_region(frba_t *frba, int region_type)
region.base = (frba->flreg4 & 0x00000fff) << 12;
region.limit = ((frba->flreg4 & 0x0fff0000) >> 4) | 0xfff;
break;
case 5:
region.base = (frba->flreg5 & 0x00000fff) << 12;
region.limit = ((frba->flreg5 & 0x0fff0000) >> 4) | 0xfff;
break;
case 6:
region.base = (frba->flreg6 & 0x00000fff) << 12;
region.limit = ((frba->flreg6 & 0x0fff0000) >> 4) | 0xfff;
break;
case 7:
region.base = (frba->flreg7 & 0x00000fff) << 12;
region.limit = ((frba->flreg7 & 0x0fff0000) >> 4) | 0xfff;
break;
case 8:
region.base = (frba->flreg8 & 0x00000fff) << 12;
region.limit = ((frba->flreg8 & 0x0fff0000) >> 4) | 0xfff;
break;
default:
fprintf(stderr, "Invalid region type.\n");
fprintf(stderr, "Invalid region type %d.\n", region_type);
exit (EXIT_FAILURE);
}
@ -132,7 +184,7 @@ static void set_region(frba_t *frba, int region_type, region_t region)
static const char *region_name(int region_type)
{
if (region_type < 0 || region_type >= NUM_REGIONS) {
if (region_type < 0 || region_type >= MAX_REGIONS) {
fprintf(stderr, "Invalid region type.\n");
exit (EXIT_FAILURE);
}
@ -142,7 +194,7 @@ static const char *region_name(int region_type)
static const char *region_name_short(int region_type)
{
if (region_type < 0 || region_type >= NUM_REGIONS) {
if (region_type < 0 || region_type >= MAX_REGIONS) {
fprintf(stderr, "Invalid region type.\n");
exit (EXIT_FAILURE);
}
@ -154,7 +206,7 @@ static int region_num(const char *name)
{
int i;
for (i = 0; i < NUM_REGIONS; i++) {
for (i = 0; i < MAX_REGIONS; i++) {
if (strcasecmp(name, region_names[i].pretty) == 0)
return i;
if (strcasecmp(name, region_names[i].terse) == 0)
@ -166,16 +218,20 @@ static int region_num(const char *name)
static const char *region_filename(int region_type)
{
static const char *region_filenames[NUM_REGIONS] = {
static const char *region_filenames[MAX_REGIONS] = {
"flashregion_0_flashdescriptor.bin",
"flashregion_1_bios.bin",
"flashregion_2_intel_me.bin",
"flashregion_3_gbe.bin",
"flashregion_4_platform_data.bin"
"flashregion_4_platform_data.bin",
"flashregion_5_reserved.bin",
"flashregion_6_reserved.bin",
"flashregion_7_reserved.bin",
"flashregion_8_ec.bin",
};
if (region_type < 0 || region_type >= NUM_REGIONS) {
fprintf(stderr, "Invalid region type.\n");
if (region_type < 0 || region_type >= MAX_REGIONS) {
fprintf(stderr, "Invalid region type %d.\n", region_type);
exit (EXIT_FAILURE);
}
@ -210,6 +266,17 @@ static void dump_frba(frba_t * frba)
dump_region(3, frba);
printf("FLREG4: 0x%08x\n", frba->flreg4);
dump_region(4, frba);
if (ifd_version >= IFD_VERSION_2) {
printf("FLREG5: 0x%08x\n", frba->flreg5);
dump_region(5, frba);
printf("FLREG6: 0x%08x\n", frba->flreg6);
dump_region(6, frba);
printf("FLREG7: 0x%08x\n", frba->flreg7);
dump_region(7, frba);
printf("FLREG8: 0x%08x\n", frba->flreg8);
dump_region(8, frba);
}
}
static void dump_frba_layout(frba_t * frba, char *layout_fname)
@ -225,7 +292,7 @@ static void dump_frba_layout(frba_t * frba, char *layout_fname)
exit(EXIT_FAILURE);
}
for (i = 0; i < NUM_REGIONS; i++) {
for (i = 0; i < MAX_REGIONS; i++) {
dump_region_layout(buf, bufsize, i, frba);
if (write(layout_fd, buf, strlen(buf)) < 0) {
perror("Could not write to file");
@ -245,9 +312,22 @@ static void decode_spi_frequency(unsigned int freq)
case SPI_FREQUENCY_33MHZ:
printf("33MHz");
break;
case SPI_FREQUENCY_50MHZ:
case SPI_FREQUENCY_48MHZ:
printf("48MHz");
break;
case SPI_FREQUENCY_50MHZ_30MHZ:
switch (ifd_version) {
case IFD_VERSION_1:
printf("50MHz");
break;
case IFD_VERSION_2:
printf("30MHz");
break;
}
break;
case SPI_FREQUENCY_17MHZ:
printf("17MHz");
break;
default:
printf("unknown<%x>MHz", freq);
}
@ -274,6 +354,15 @@ static void decode_component_density(unsigned int density)
case COMPONENT_DENSITY_16MB:
printf("16MB");
break;
case COMPONENT_DENSITY_32MB:
printf("32MB");
break;
case COMPONENT_DENSITY_64MB:
printf("64MB");
break;
case COMPONENT_DENSITY_UNUSED:
printf("UNUSED");
break;
default:
printf("unknown<%x>MB", density);
}
@ -295,10 +384,22 @@ static void dump_fcba(fcba_t * fcba)
(fcba->flcomp & (1 << 20))?"":"not ");
printf("\n Read Clock Frequency: ");
decode_spi_frequency((fcba->flcomp >> 17) & 7);
switch (ifd_version) {
case IFD_VERSION_1:
printf("\n Component 2 Density: ");
decode_component_density((fcba->flcomp >> 3) & 7);
printf("\n Component 1 Density: ");
decode_component_density(fcba->flcomp & 7);
break;
case IFD_VERSION_2:
printf("\n Component 2 Density: ");
decode_component_density((fcba->flcomp >> 4) & 0xf);
printf("\n Component 1 Density: ");
decode_component_density(fcba->flcomp & 0xf);
break;
}
printf("\n");
printf("FLILL 0x%08x\n", fcba->flill);
printf(" Invalid Instruction 3: 0x%02x\n",
@ -339,6 +440,9 @@ static void dump_fpsba(fpsba_t * fpsba)
static void decode_flmstr(uint32_t flmstr)
{
if (ifd_version >= IFD_VERSION_2)
printf(" EC Region Write Access: %s\n",
(flmstr & (1 << 29)) ? "enabled" : "disabled");
printf(" Platform Data Region Write Access: %s\n",
(flmstr & (1 << 28)) ? "enabled" : "disabled");
printf(" GbE Region Write Access: %s\n",
@ -350,6 +454,9 @@ static void decode_flmstr(uint32_t flmstr)
printf(" Flash Descriptor Write Access: %s\n",
(flmstr & (1 << 24)) ? "enabled" : "disabled");
if (ifd_version >= IFD_VERSION_2)
printf(" EC Region Read Access: %s\n",
(flmstr & (1 << 21)) ? "enabled" : "disabled");
printf(" Platform Data Region Read Access: %s\n",
(flmstr & (1 << 20)) ? "enabled" : "disabled");
printf(" GbE Region Read Access: %s\n",
@ -374,6 +481,10 @@ static void dump_fmba(fmba_t * fmba)
decode_flmstr(fmba->flmstr2);
printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
decode_flmstr(fmba->flmstr3);
if (ifd_version >= IFD_VERSION_2) {
printf("FLMSTR5: 0x%08x (EC)\n", fmba->flmstr5);
decode_flmstr(fmba->flmstr5);
}
}
static void dump_fmsba(fmsba_t * fmsba)
@ -528,6 +639,7 @@ static void dump_layout(char *image, int size, char *layout_fname)
static void write_regions(char *image, int size)
{
int i;
int max_regions = MAX_REGIONS;
fdbar_t *fdb = find_fd(image, size);
if (!fdb)
@ -536,7 +648,11 @@ static void write_regions(char *image, int size)
frba_t *frba =
(frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
for (i = 0; i < NUM_REGIONS; i++) {
/* Older descriptor images have fewer regions */
if (ifd_version < IFD_VERSION_2)
max_regions = MAX_REGIONS_OLD;
for (i = 0; i < max_regions; i++) {
region_t region = get_region(frba, i);
dump_region(i, frba);
if (region.size > 0) {
@ -601,9 +717,19 @@ static void set_em100_mode(char *filename, char *image, int size)
{
fdbar_t *fdb = find_fd(image, size);
fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
int freq;
switch (ifd_version) {
case IFD_VERSION_1:
freq = SPI_FREQUENCY_20MHZ;
break;
case IFD_VERSION_2:
freq = SPI_FREQUENCY_17MHZ;
break;
}
fcba->flcomp &= ~(1 << 30);
set_spi_frequency(filename, image, size, SPI_FREQUENCY_20MHZ);
set_spi_frequency(filename, image, size, freq);
}
static void lock_descriptor(char *filename, char *image, int size)
@ -736,8 +862,8 @@ void new_layout(char *filename, char *image, int size, char *layout_fname)
char layout_region_name[256];
int i, j;
int region_number;
region_t current_regions[NUM_REGIONS];
region_t new_regions[NUM_REGIONS];
region_t current_regions[MAX_REGIONS];
region_t new_regions[MAX_REGIONS];
int new_extent = 0;
char *new_image;
@ -749,7 +875,7 @@ void new_layout(char *filename, char *image, int size, char *layout_fname)
frba_t *frba =
(frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
for (i = 0; i < NUM_REGIONS; i++) {
for (i = 0; i < MAX_REGIONS; i++) {
current_regions[i] = get_region(frba, i);
new_regions[i] = get_region(frba, i);
}
@ -793,7 +919,7 @@ void new_layout(char *filename, char *image, int size, char *layout_fname)
fclose(romlayout);
/* check new layout */
for (i = 0; i < NUM_REGIONS; i++) {
for (i = 0; i < MAX_REGIONS; i++) {
if (new_regions[i].size == 0)
continue;
@ -804,7 +930,7 @@ void new_layout(char *filename, char *image, int size, char *layout_fname)
printf(" This may result in an unusable image.\n");
}
for (j = i + 1; j < NUM_REGIONS; j++) {
for (j = i + 1; j < MAX_REGIONS; j++) {
if (regions_collide(new_regions[i], new_regions[j])) {
fprintf(stderr, "Regions would overlap.\n");
exit(EXIT_FAILURE);
@ -826,7 +952,7 @@ void new_layout(char *filename, char *image, int size, char *layout_fname)
/* copy regions to a new image */
new_image = malloc(new_extent);
memset(new_image, 0xff, new_extent);
for (i = 0; i < NUM_REGIONS; i++) {
for (i = 0; i < MAX_REGIONS; i++) {
int copy_size = new_regions[i].size;
int offset_current = 0, offset_new = 0;
region_t current = current_regions[i];
@ -864,7 +990,7 @@ void new_layout(char *filename, char *image, int size, char *layout_fname)
exit(EXIT_FAILURE);
frba = (frba_t *) (new_image + (((fdb->flmap0 >> 16) & 0xff) << 4));
for (i = 1; i < NUM_REGIONS; i++) {
for (i = 1; i < MAX_REGIONS; i++) {
set_region(frba, i, new_regions[i]);
}
@ -897,7 +1023,7 @@ static void print_usage(const char *name)
" -x | --extract: extract intel fd modules\n"
" -i | --inject <region>:<module> inject file <module> into region <region>\n"
" -n | --newlayout <filename> update regions using a flashrom layout file\n"
" -s | --spifreq <20|33|50> set the SPI frequency\n"
" -s | --spifreq <17|20|30|33|48|50> set the SPI frequency\n"
" -e | --em100 set SPI frequency to 20MHz and disable\n"
" Dual Output Fast Read Support\n"
" -l | --lock Lock firmware descriptor and ME region\n"
@ -973,6 +1099,8 @@ int main(int argc, char *argv[])
region_type = 3;
else if (!strcasecmp("Platform", region_type_string))
region_type = 4;
else if (!strcasecmp("EC", region_type_string))
region_type = 8;
if (region_type == -1) {
fprintf(stderr, "No such region type: '%s'\n\n",
region_type_string);
@ -994,14 +1122,23 @@ int main(int argc, char *argv[])
// Parse the requested SPI frequency
inputfreq = strtol(optarg, NULL, 0);
switch (inputfreq) {
case 17:
spifreq = SPI_FREQUENCY_17MHZ;
break;
case 20:
spifreq = SPI_FREQUENCY_20MHZ;
break;
case 30:
spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
break;
case 33:
spifreq = SPI_FREQUENCY_33MHZ;
break;
case 48:
spifreq = SPI_FREQUENCY_48MHZ;
break;
case 50:
spifreq = SPI_FREQUENCY_50MHZ;
spifreq = SPI_FREQUENCY_50MHZ_30MHZ;
break;
default:
fprintf(stderr, "Invalid SPI Frequency: %d\n",
@ -1091,6 +1228,8 @@ int main(int argc, char *argv[])
close(bios_fd);
check_ifd_version(image, size);
if (mode_dump)
dump_fd(image, size);

View File

@ -18,14 +18,21 @@
*/
#include <stdint.h>
#define IFDTOOL_VERSION "1.1"
#define IFDTOOL_VERSION "1.2"
enum ifd_version {
IFD_VERSION_1,
IFD_VERSION_2,
};
#define LAYOUT_LINELEN 80
enum spi_frequency {
SPI_FREQUENCY_20MHZ = 0,
SPI_FREQUENCY_33MHZ = 1,
SPI_FREQUENCY_50MHZ = 4,
SPI_FREQUENCY_48MHZ = 2,
SPI_FREQUENCY_50MHZ_30MHZ = 4,
SPI_FREQUENCY_17MHZ = 6,
};
enum component_density {
@ -35,6 +42,9 @@ enum component_density {
COMPONENT_DENSITY_4MB = 3,
COMPONENT_DENSITY_8MB = 4,
COMPONENT_DENSITY_16MB = 5,
COMPONENT_DENSITY_32MB = 6,
COMPONENT_DENSITY_64MB = 7,
COMPONENT_DENSITY_UNUSED = 0xf
};
// flash descriptor
@ -48,12 +58,18 @@ typedef struct {
} __attribute__((packed)) fdbar_t;
// regions
#define MAX_REGIONS 9
#define MAX_REGIONS_OLD 5
typedef struct {
uint32_t flreg0;
uint32_t flreg1;
uint32_t flreg2;
uint32_t flreg3;
uint32_t flreg4;
uint32_t flreg5;
uint32_t flreg6;
uint32_t flreg7;
uint32_t flreg8;
} __attribute__((packed)) frba_t;
// component section
@ -90,6 +106,8 @@ typedef struct {
uint32_t flmstr1;
uint32_t flmstr2;
uint32_t flmstr3;
uint32_t flmstr4;
uint32_t flmstr5;
} __attribute__((packed)) fmba_t;
// processor strap