a73b93157f
It encourages users from writing to the FSF without giving an address. Linux also prefers to drop that and their checkpatch.pl (that we imported) looks out for that. This is the result of util/scripts/no-fsf-addresses.sh with no further editing. Change-Id: Ie96faea295fe001911d77dbc51e9a6789558fbd6 Signed-off-by: Patrick Georgi <pgeorgi@chromium.org> Reviewed-on: http://review.coreboot.org/11888 Tested-by: build bot (Jenkins) Reviewed-by: Alexandru Gagniuc <mr.nuke.me@gmail.com> Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
1317 lines
35 KiB
C
1317 lines
35 KiB
C
/*
|
|
* ifdtool - dump Intel Firmware Descriptor information
|
|
*
|
|
* Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <getopt.h>
|
|
#include <fcntl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include "ifdtool.h"
|
|
|
|
#ifndef O_BINARY
|
|
#define O_BINARY 0
|
|
#endif
|
|
|
|
static int ifd_version;
|
|
|
|
static const struct region_name region_names[MAX_REGIONS] = {
|
|
{ "Flash Descriptor", "fd" },
|
|
{ "BIOS", "bios" },
|
|
{ "Intel ME", "me" },
|
|
{ "GbE", "gbe" },
|
|
{ "Platform Data", "pd" },
|
|
{ "Reserved", "res1" },
|
|
{ "Reserved", "res2" },
|
|
{ "Reserved", "res3" },
|
|
{ "EC", "ec" },
|
|
};
|
|
|
|
static fdbar_t *find_fd(char *image, int size)
|
|
{
|
|
int i, found = 0;
|
|
|
|
/* Scan for FD signature */
|
|
for (i = 0; i < (size - 4); i += 4) {
|
|
if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
|
|
found = 1;
|
|
break; // signature found.
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
printf("No Flash Descriptor found in this image\n");
|
|
return NULL;
|
|
}
|
|
|
|
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)
|
|
{
|
|
int base_mask;
|
|
int limit_mask;
|
|
uint32_t *flreg;
|
|
region_t region;
|
|
|
|
if (ifd_version >= IFD_VERSION_2)
|
|
base_mask = 0x7fff;
|
|
else
|
|
base_mask = 0xfff;
|
|
|
|
limit_mask = base_mask << 16;
|
|
|
|
switch (region_type) {
|
|
case 0:
|
|
flreg = &frba->flreg0;
|
|
break;
|
|
case 1:
|
|
flreg = &frba->flreg1;
|
|
break;
|
|
case 2:
|
|
flreg = &frba->flreg2;
|
|
break;
|
|
case 3:
|
|
flreg = &frba->flreg3;
|
|
break;
|
|
case 4:
|
|
flreg = &frba->flreg4;
|
|
break;
|
|
case 5:
|
|
flreg = &frba->flreg5;
|
|
break;
|
|
case 6:
|
|
flreg = &frba->flreg6;
|
|
break;
|
|
case 7:
|
|
flreg = &frba->flreg7;
|
|
break;
|
|
case 8:
|
|
flreg = &frba->flreg8;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "Invalid region type %d.\n", region_type);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
region.base = (*flreg & base_mask) << 12;
|
|
region.limit = ((*flreg & limit_mask) >> 4) | 0xfff;
|
|
region.size = region.limit - region.base + 1;
|
|
|
|
if (region.size < 0)
|
|
region.size = 0;
|
|
|
|
return region;
|
|
}
|
|
|
|
static void set_region(frba_t *frba, int region_type, region_t region)
|
|
{
|
|
switch (region_type) {
|
|
case 0:
|
|
frba->flreg0 = (((region.limit >> 12) & 0x7fff) << 16)
|
|
| ((region.base >> 12) & 0x7fff);
|
|
break;
|
|
case 1:
|
|
frba->flreg1 = (((region.limit >> 12) & 0x7fff) << 16)
|
|
| ((region.base >> 12) & 0x7fff);
|
|
break;
|
|
case 2:
|
|
frba->flreg2 = (((region.limit >> 12) & 0x7fff) << 16)
|
|
| ((region.base >> 12) & 0x7fff);
|
|
break;
|
|
case 3:
|
|
frba->flreg3 = (((region.limit >> 12) & 0x7fff) << 16)
|
|
| ((region.base >> 12) & 0x7fff);
|
|
break;
|
|
case 4:
|
|
frba->flreg4 = (((region.limit >> 12) & 0x7fff) << 16)
|
|
| ((region.base >> 12) & 0x7fff);
|
|
break;
|
|
default:
|
|
fprintf(stderr, "Invalid region type.\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
static const char *region_name(int region_type)
|
|
{
|
|
if (region_type < 0 || region_type >= MAX_REGIONS) {
|
|
fprintf(stderr, "Invalid region type.\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
return region_names[region_type].pretty;
|
|
}
|
|
|
|
static const char *region_name_short(int region_type)
|
|
{
|
|
if (region_type < 0 || region_type >= MAX_REGIONS) {
|
|
fprintf(stderr, "Invalid region type.\n");
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
return region_names[region_type].terse;
|
|
}
|
|
|
|
static int region_num(const char *name)
|
|
{
|
|
int 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)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static const char *region_filename(int region_type)
|
|
{
|
|
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_5_reserved.bin",
|
|
"flashregion_6_reserved.bin",
|
|
"flashregion_7_reserved.bin",
|
|
"flashregion_8_ec.bin",
|
|
};
|
|
|
|
if (region_type < 0 || region_type >= MAX_REGIONS) {
|
|
fprintf(stderr, "Invalid region type %d.\n", region_type);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
return region_filenames[region_type];
|
|
}
|
|
|
|
static void dump_region(int num, frba_t *frba)
|
|
{
|
|
region_t region = get_region(frba, num);
|
|
printf(" Flash Region %d (%s): %08x - %08x %s\n",
|
|
num, region_name(num), region.base, region.limit,
|
|
region.size < 1 ? "(unused)" : "");
|
|
}
|
|
|
|
static void dump_region_layout(char *buf, size_t bufsize, int num, frba_t *frba)
|
|
{
|
|
region_t region = get_region(frba, num);
|
|
snprintf(buf, bufsize, "%08x:%08x %s\n",
|
|
region.base, region.limit, region_name_short(num));
|
|
}
|
|
|
|
static void dump_frba(frba_t * frba)
|
|
{
|
|
printf("Found Region Section\n");
|
|
printf("FLREG0: 0x%08x\n", frba->flreg0);
|
|
dump_region(0, frba);
|
|
printf("FLREG1: 0x%08x\n", frba->flreg1);
|
|
dump_region(1, frba);
|
|
printf("FLREG2: 0x%08x\n", frba->flreg2);
|
|
dump_region(2, frba);
|
|
printf("FLREG3: 0x%08x\n", frba->flreg3);
|
|
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)
|
|
{
|
|
char buf[LAYOUT_LINELEN];
|
|
size_t bufsize = LAYOUT_LINELEN;
|
|
int i;
|
|
|
|
int layout_fd = open(layout_fname, O_WRONLY | O_CREAT | O_TRUNC,
|
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
if (layout_fd == -1) {
|
|
perror("Could not open file");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
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");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
close(layout_fd);
|
|
printf("Wrote layout to %s\n", layout_fname);
|
|
}
|
|
|
|
static void decode_spi_frequency(unsigned int freq)
|
|
{
|
|
switch (freq) {
|
|
case SPI_FREQUENCY_20MHZ:
|
|
printf("20MHz");
|
|
break;
|
|
case SPI_FREQUENCY_33MHZ:
|
|
printf("33MHz");
|
|
break;
|
|
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);
|
|
}
|
|
}
|
|
|
|
static void decode_component_density(unsigned int density)
|
|
{
|
|
switch (density) {
|
|
case COMPONENT_DENSITY_512KB:
|
|
printf("512KB");
|
|
break;
|
|
case COMPONENT_DENSITY_1MB:
|
|
printf("1MB");
|
|
break;
|
|
case COMPONENT_DENSITY_2MB:
|
|
printf("2MB");
|
|
break;
|
|
case COMPONENT_DENSITY_4MB:
|
|
printf("4MB");
|
|
break;
|
|
case COMPONENT_DENSITY_8MB:
|
|
printf("8MB");
|
|
break;
|
|
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);
|
|
}
|
|
}
|
|
|
|
static void dump_fcba(fcba_t * fcba)
|
|
{
|
|
printf("\nFound Component Section\n");
|
|
printf("FLCOMP 0x%08x\n", fcba->flcomp);
|
|
printf(" Dual Output Fast Read Support: %ssupported\n",
|
|
(fcba->flcomp & (1 << 30))?"":"not ");
|
|
printf(" Read ID/Read Status Clock Frequency: ");
|
|
decode_spi_frequency((fcba->flcomp >> 27) & 7);
|
|
printf("\n Write/Erase Clock Frequency: ");
|
|
decode_spi_frequency((fcba->flcomp >> 24) & 7);
|
|
printf("\n Fast Read Clock Frequency: ");
|
|
decode_spi_frequency((fcba->flcomp >> 21) & 7);
|
|
printf("\n Fast Read Support: %ssupported",
|
|
(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",
|
|
(fcba->flill >> 24) & 0xff);
|
|
printf(" Invalid Instruction 2: 0x%02x\n",
|
|
(fcba->flill >> 16) & 0xff);
|
|
printf(" Invalid Instruction 1: 0x%02x\n",
|
|
(fcba->flill >> 8) & 0xff);
|
|
printf(" Invalid Instruction 0: 0x%02x\n",
|
|
fcba->flill & 0xff);
|
|
printf("FLPB 0x%08x\n", fcba->flpb);
|
|
printf(" Flash Partition Boundary Address: 0x%06x\n\n",
|
|
(fcba->flpb & 0xfff) << 12);
|
|
}
|
|
|
|
static void dump_fpsba(fpsba_t * fpsba)
|
|
{
|
|
printf("Found PCH Strap Section\n");
|
|
printf("PCHSTRP0: 0x%08x\n", fpsba->pchstrp0);
|
|
printf("PCHSTRP1: 0x%08x\n", fpsba->pchstrp1);
|
|
printf("PCHSTRP2: 0x%08x\n", fpsba->pchstrp2);
|
|
printf("PCHSTRP3: 0x%08x\n", fpsba->pchstrp3);
|
|
printf("PCHSTRP4: 0x%08x\n", fpsba->pchstrp4);
|
|
printf("PCHSTRP5: 0x%08x\n", fpsba->pchstrp5);
|
|
printf("PCHSTRP6: 0x%08x\n", fpsba->pchstrp6);
|
|
printf("PCHSTRP7: 0x%08x\n", fpsba->pchstrp7);
|
|
printf("PCHSTRP8: 0x%08x\n", fpsba->pchstrp8);
|
|
printf("PCHSTRP9: 0x%08x\n", fpsba->pchstrp9);
|
|
printf("PCHSTRP10: 0x%08x\n", fpsba->pchstrp10);
|
|
printf("PCHSTRP11: 0x%08x\n", fpsba->pchstrp11);
|
|
printf("PCHSTRP12: 0x%08x\n", fpsba->pchstrp12);
|
|
printf("PCHSTRP13: 0x%08x\n", fpsba->pchstrp13);
|
|
printf("PCHSTRP14: 0x%08x\n", fpsba->pchstrp14);
|
|
printf("PCHSTRP15: 0x%08x\n", fpsba->pchstrp15);
|
|
printf("PCHSTRP16: 0x%08x\n", fpsba->pchstrp16);
|
|
printf("PCHSTRP17: 0x%08x\n\n", fpsba->pchstrp17);
|
|
}
|
|
|
|
static void decode_flmstr(uint32_t flmstr)
|
|
{
|
|
int wr_shift, rd_shift;
|
|
if (ifd_version >= IFD_VERSION_2) {
|
|
wr_shift = FLMSTR_WR_SHIFT_V2;
|
|
rd_shift = FLMSTR_RD_SHIFT_V2;
|
|
} else {
|
|
wr_shift = FLMSTR_WR_SHIFT_V1;
|
|
rd_shift = FLMSTR_RD_SHIFT_V1;
|
|
}
|
|
|
|
/* EC region access only available on v2+ */
|
|
if (ifd_version >= IFD_VERSION_2)
|
|
printf(" EC Region Write Access: %s\n",
|
|
(flmstr & (1 << (wr_shift + 8))) ?
|
|
"enabled" : "disabled");
|
|
printf(" Platform Data Region Write Access: %s\n",
|
|
(flmstr & (1 << (wr_shift + 4))) ? "enabled" : "disabled");
|
|
printf(" GbE Region Write Access: %s\n",
|
|
(flmstr & (1 << (wr_shift + 3))) ? "enabled" : "disabled");
|
|
printf(" Intel ME Region Write Access: %s\n",
|
|
(flmstr & (1 << (wr_shift + 2))) ? "enabled" : "disabled");
|
|
printf(" Host CPU/BIOS Region Write Access: %s\n",
|
|
(flmstr & (1 << (wr_shift + 1))) ? "enabled" : "disabled");
|
|
printf(" Flash Descriptor Write Access: %s\n",
|
|
(flmstr & (1 << wr_shift)) ? "enabled" : "disabled");
|
|
|
|
if (ifd_version >= IFD_VERSION_2)
|
|
printf(" EC Region Read Access: %s\n",
|
|
(flmstr & (1 << (rd_shift + 8))) ?
|
|
"enabled" : "disabled");
|
|
printf(" Platform Data Region Read Access: %s\n",
|
|
(flmstr & (1 << (rd_shift + 4))) ? "enabled" : "disabled");
|
|
printf(" GbE Region Read Access: %s\n",
|
|
(flmstr & (1 << (rd_shift + 3))) ? "enabled" : "disabled");
|
|
printf(" Intel ME Region Read Access: %s\n",
|
|
(flmstr & (1 << (rd_shift + 2))) ? "enabled" : "disabled");
|
|
printf(" Host CPU/BIOS Region Read Access: %s\n",
|
|
(flmstr & (1 << (rd_shift + 1))) ? "enabled" : "disabled");
|
|
printf(" Flash Descriptor Read Access: %s\n",
|
|
(flmstr & (1 << rd_shift)) ? "enabled" : "disabled");
|
|
|
|
/* Requestor ID doesn't exist for ifd 2 */
|
|
if (ifd_version < IFD_VERSION_2)
|
|
printf(" Requester ID: 0x%04x\n\n",
|
|
flmstr & 0xffff);
|
|
}
|
|
|
|
static void dump_fmba(fmba_t * fmba)
|
|
{
|
|
printf("Found Master Section\n");
|
|
printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
|
|
decode_flmstr(fmba->flmstr1);
|
|
printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
|
|
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)
|
|
{
|
|
printf("Found Processor Strap Section\n");
|
|
printf("????: 0x%08x\n", fmsba->data[0]);
|
|
printf("????: 0x%08x\n", fmsba->data[1]);
|
|
printf("????: 0x%08x\n", fmsba->data[2]);
|
|
printf("????: 0x%08x\n", fmsba->data[3]);
|
|
}
|
|
|
|
static void dump_jid(uint32_t jid)
|
|
{
|
|
printf(" SPI Componend Device ID 1: 0x%02x\n",
|
|
(jid >> 16) & 0xff);
|
|
printf(" SPI Componend Device ID 0: 0x%02x\n",
|
|
(jid >> 8) & 0xff);
|
|
printf(" SPI Componend Vendor ID: 0x%02x\n",
|
|
jid & 0xff);
|
|
}
|
|
|
|
static void dump_vscc(uint32_t vscc)
|
|
{
|
|
printf(" Lower Erase Opcode: 0x%02x\n",
|
|
vscc >> 24);
|
|
printf(" Lower Write Enable on Write Status: 0x%02x\n",
|
|
vscc & (1 << 20) ? 0x06 : 0x50);
|
|
printf(" Lower Write Status Required: %s\n",
|
|
vscc & (1 << 19) ? "Yes" : "No");
|
|
printf(" Lower Write Granularity: %d bytes\n",
|
|
vscc & (1 << 18) ? 64 : 1);
|
|
printf(" Lower Block / Sector Erase Size: ");
|
|
switch ((vscc >> 16) & 0x3) {
|
|
case 0:
|
|
printf("256 Byte\n");
|
|
break;
|
|
case 1:
|
|
printf("4KB\n");
|
|
break;
|
|
case 2:
|
|
printf("8KB\n");
|
|
break;
|
|
case 3:
|
|
printf("64KB\n");
|
|
break;
|
|
}
|
|
|
|
printf(" Upper Erase Opcode: 0x%02x\n",
|
|
(vscc >> 8) & 0xff);
|
|
printf(" Upper Write Enable on Write Status: 0x%02x\n",
|
|
vscc & (1 << 4) ? 0x06 : 0x50);
|
|
printf(" Upper Write Status Required: %s\n",
|
|
vscc & (1 << 3) ? "Yes" : "No");
|
|
printf(" Upper Write Granularity: %d bytes\n",
|
|
vscc & (1 << 2) ? 64 : 1);
|
|
printf(" Upper Block / Sector Erase Size: ");
|
|
switch (vscc & 0x3) {
|
|
case 0:
|
|
printf("256 Byte\n");
|
|
break;
|
|
case 1:
|
|
printf("4KB\n");
|
|
break;
|
|
case 2:
|
|
printf("8KB\n");
|
|
break;
|
|
case 3:
|
|
printf("64KB\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void dump_vtba(vtba_t *vtba, int vtl)
|
|
{
|
|
int i;
|
|
int num = (vtl >> 1) < 8 ? (vtl >> 1) : 8;
|
|
|
|
printf("ME VSCC table:\n");
|
|
for (i = 0; i < num; i++) {
|
|
printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
|
|
dump_jid(vtba->entry[i].jid);
|
|
printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
|
|
dump_vscc(vtba->entry[i].vscc);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
static void dump_oem(uint8_t *oem)
|
|
{
|
|
int i, j;
|
|
printf("OEM Section:\n");
|
|
for (i = 0; i < 4; i++) {
|
|
printf("%02x:", i << 4);
|
|
for (j = 0; j < 16; j++)
|
|
printf(" %02x", oem[(i<<4)+j]);
|
|
printf ("\n");
|
|
}
|
|
printf ("\n");
|
|
}
|
|
|
|
static void dump_fd(char *image, int size)
|
|
{
|
|
fdbar_t *fdb = find_fd(image, size);
|
|
if (!fdb)
|
|
exit(EXIT_FAILURE);
|
|
|
|
printf("FLMAP0: 0x%08x\n", fdb->flmap0);
|
|
printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
|
|
printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
|
|
printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
|
|
printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
|
|
|
|
printf("FLMAP1: 0x%08x\n", fdb->flmap1);
|
|
printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
|
|
printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
|
|
printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
|
|
printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
|
|
|
|
printf("FLMAP2: 0x%08x\n", fdb->flmap2);
|
|
printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
|
|
printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
|
|
|
|
printf("FLUMAP1: 0x%08x\n", fdb->flumap1);
|
|
printf(" Intel ME VSCC Table Length (VTL): %d\n",
|
|
(fdb->flumap1 >> 8) & 0xff);
|
|
printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
|
|
(fdb->flumap1 & 0xff) << 4);
|
|
dump_vtba((vtba_t *)
|
|
(image + ((fdb->flumap1 & 0xff) << 4)),
|
|
(fdb->flumap1 >> 8) & 0xff);
|
|
dump_oem((uint8_t *)image + 0xf00);
|
|
dump_frba((frba_t *)
|
|
(image + (((fdb->flmap0 >> 16) & 0xff) << 4)));
|
|
dump_fcba((fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4)));
|
|
dump_fpsba((fpsba_t *)
|
|
(image + (((fdb->flmap1 >> 16) & 0xff) << 4)));
|
|
dump_fmba((fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4)));
|
|
dump_fmsba((fmsba_t *) (image + (((fdb->flmap2) & 0xff) << 4)));
|
|
}
|
|
|
|
static void dump_layout(char *image, int size, char *layout_fname)
|
|
{
|
|
fdbar_t *fdb = find_fd(image, size);
|
|
if (!fdb)
|
|
exit(EXIT_FAILURE);
|
|
|
|
dump_frba_layout((frba_t *)
|
|
(image + (((fdb->flmap0 >> 16) & 0xff) << 4)),
|
|
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)
|
|
exit(EXIT_FAILURE);
|
|
|
|
frba_t *frba =
|
|
(frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
|
|
|
|
/* 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) {
|
|
int region_fd;
|
|
region_fd = open(region_filename(i),
|
|
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
if (region_fd < 0) {
|
|
perror("Error while trying to open file");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if (write(region_fd, image + region.base, region.size) != region.size)
|
|
perror("Error while writing");
|
|
close(region_fd);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void write_image(char *filename, char *image, int size)
|
|
{
|
|
char new_filename[FILENAME_MAX]; // allow long file names
|
|
int new_fd;
|
|
|
|
// - 5: leave room for ".new\0"
|
|
strncpy(new_filename, filename, FILENAME_MAX - 5);
|
|
strncat(new_filename, ".new", FILENAME_MAX - strlen(filename));
|
|
|
|
printf("Writing new image to %s\n", new_filename);
|
|
|
|
// Now write out new image
|
|
new_fd = open(new_filename,
|
|
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
if (new_fd < 0) {
|
|
perror("Error while trying to open file");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if (write(new_fd, image, size) != size)
|
|
perror("Error while writing");
|
|
close(new_fd);
|
|
}
|
|
|
|
static void set_spi_frequency(char *filename, char *image, int size,
|
|
enum spi_frequency freq)
|
|
{
|
|
fdbar_t *fdb = find_fd(image, size);
|
|
fcba_t *fcba = (fcba_t *) (image + (((fdb->flmap0) & 0xff) << 4));
|
|
|
|
/* clear bits 21-29 */
|
|
fcba->flcomp &= ~0x3fe00000;
|
|
/* Read ID and Read Status Clock Frequency */
|
|
fcba->flcomp |= freq << 27;
|
|
/* Write and Erase Clock Frequency */
|
|
fcba->flcomp |= freq << 24;
|
|
/* Fast Read Clock Frequency */
|
|
fcba->flcomp |= freq << 21;
|
|
|
|
write_image(filename, image, size);
|
|
}
|
|
|
|
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;
|
|
default:
|
|
freq = SPI_FREQUENCY_17MHZ;
|
|
break;
|
|
}
|
|
|
|
fcba->flcomp &= ~(1 << 30);
|
|
set_spi_frequency(filename, image, size, freq);
|
|
}
|
|
|
|
static void lock_descriptor(char *filename, char *image, int size)
|
|
{
|
|
int wr_shift, rd_shift;
|
|
fdbar_t *fdb = find_fd(image, size);
|
|
fmba_t *fmba = (fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4));
|
|
/* TODO: Dynamically take Platform Data Region and GbE Region
|
|
* into regard.
|
|
*/
|
|
|
|
if (ifd_version >= IFD_VERSION_2) {
|
|
wr_shift = FLMSTR_WR_SHIFT_V2;
|
|
rd_shift = FLMSTR_RD_SHIFT_V2;
|
|
|
|
/* Clear non-reserved bits */
|
|
fmba->flmstr1 &= 0xff;
|
|
fmba->flmstr2 &= 0xff;
|
|
fmba->flmstr3 &= 0xff;
|
|
} else {
|
|
wr_shift = FLMSTR_WR_SHIFT_V1;
|
|
rd_shift = FLMSTR_RD_SHIFT_V1;
|
|
|
|
fmba->flmstr1 = 0;
|
|
fmba->flmstr2 = 0;
|
|
/* Requestor ID */
|
|
fmba->flmstr3 = 0x118;
|
|
}
|
|
|
|
/* CPU/BIOS can read descriptor, BIOS, and GbE. */
|
|
fmba->flmstr1 |= 0xb << rd_shift;
|
|
/* CPU/BIOS can write BIOS and GbE. */
|
|
fmba->flmstr1 |= 0xa << wr_shift;
|
|
/* ME can read descriptor, ME, and GbE. */
|
|
fmba->flmstr2 |= 0xd << rd_shift;
|
|
/* ME can write ME and GbE. */
|
|
fmba->flmstr2 |= 0xc << wr_shift;
|
|
/* GbE can write only GbE. */
|
|
fmba->flmstr3 |= 0x8 << rd_shift;
|
|
/* GbE can read only GbE. */
|
|
fmba->flmstr3 |= 0x8 << wr_shift;
|
|
|
|
write_image(filename, image, size);
|
|
}
|
|
|
|
static void unlock_descriptor(char *filename, char *image, int size)
|
|
{
|
|
fdbar_t *fdb = find_fd(image, size);
|
|
fmba_t *fmba = (fmba_t *) (image + (((fdb->flmap1) & 0xff) << 4));
|
|
|
|
if (ifd_version >= IFD_VERSION_2) {
|
|
/* Access bits for each region are read: 19:8 write: 31:20 */
|
|
fmba->flmstr1 = 0xffffff00 | (fmba->flmstr1 & 0xff);
|
|
fmba->flmstr2 = 0xffffff00 | (fmba->flmstr2 & 0xff);
|
|
fmba->flmstr3 = 0xffffff00 | (fmba->flmstr3 & 0xff);
|
|
} else {
|
|
fmba->flmstr1 = 0xffff0000;
|
|
fmba->flmstr2 = 0xffff0000;
|
|
fmba->flmstr3 = 0x08080118;
|
|
}
|
|
|
|
write_image(filename, image, size);
|
|
}
|
|
|
|
void inject_region(char *filename, char *image, int size, int region_type,
|
|
char *region_fname)
|
|
{
|
|
fdbar_t *fdb = find_fd(image, size);
|
|
if (!fdb)
|
|
exit(EXIT_FAILURE);
|
|
frba_t *frba =
|
|
(frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
|
|
|
|
region_t region = get_region(frba, region_type);
|
|
if (region.size <= 0xfff) {
|
|
fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
|
|
region_name(region_type));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
int region_fd = open(region_fname, O_RDONLY | O_BINARY);
|
|
if (region_fd == -1) {
|
|
perror("Could not open file");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
struct stat buf;
|
|
if (fstat(region_fd, &buf) == -1) {
|
|
perror("Could not stat file");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
int region_size = buf.st_size;
|
|
|
|
printf("File %s is %d bytes\n", region_fname, region_size);
|
|
|
|
if ( (region_size > region.size) || ((region_type != 1) &&
|
|
(region_size > region.size))) {
|
|
fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
|
|
" bytes. Not injecting.\n",
|
|
region_name(region_type), region.size,
|
|
region.size, region_size, region_size);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
int offset = 0;
|
|
if ((region_type == 1) && (region_size < region.size)) {
|
|
fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x)"
|
|
" bytes. Padding before injecting.\n",
|
|
region_name(region_type), region.size,
|
|
region.size, region_size, region_size);
|
|
offset = region.size - region_size;
|
|
memset(image + region.base, 0xff, offset);
|
|
}
|
|
|
|
if (size < region.base + offset + region_size) {
|
|
fprintf(stderr, "Output file is too small. (%d < %d)\n",
|
|
size, region.base + offset + region_size);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (read(region_fd, image + region.base + offset, region_size)
|
|
!= region_size) {
|
|
perror("Could not read file");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
close(region_fd);
|
|
|
|
printf("Adding %s as the %s section of %s\n",
|
|
region_fname, region_name(region_type), filename);
|
|
write_image(filename, image, size);
|
|
}
|
|
|
|
unsigned int next_pow2(unsigned int x)
|
|
{
|
|
unsigned int y = 1;
|
|
if (x == 0)
|
|
return 0;
|
|
while (y <= x)
|
|
y = y << 1;
|
|
|
|
return y;
|
|
}
|
|
|
|
/**
|
|
* Determine if two memory regions overlap.
|
|
*
|
|
* @param r1, r2 Memory regions to compare.
|
|
* @return 0 if the two regions are seperate
|
|
* @return 1 if the two regions overlap
|
|
*/
|
|
static int regions_collide(region_t r1, region_t r2)
|
|
{
|
|
if ((r1.size == 0) || (r2.size == 0))
|
|
return 0;
|
|
|
|
if ( ((r1.base >= r2.base) && (r1.base <= r2.limit)) ||
|
|
((r1.limit >= r2.base) && (r1.limit <= r2.limit)) )
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void new_layout(char *filename, char *image, int size, char *layout_fname)
|
|
{
|
|
FILE *romlayout;
|
|
char tempstr[256];
|
|
char layout_region_name[256];
|
|
int i, j;
|
|
int region_number;
|
|
region_t current_regions[MAX_REGIONS];
|
|
region_t new_regions[MAX_REGIONS];
|
|
int new_extent = 0;
|
|
char *new_image;
|
|
|
|
/* load current descriptor map and regions */
|
|
fdbar_t *fdb = find_fd(image, size);
|
|
if (!fdb)
|
|
exit(EXIT_FAILURE);
|
|
|
|
frba_t *frba =
|
|
(frba_t *) (image + (((fdb->flmap0 >> 16) & 0xff) << 4));
|
|
|
|
for (i = 0; i < MAX_REGIONS; i++) {
|
|
current_regions[i] = get_region(frba, i);
|
|
new_regions[i] = get_region(frba, i);
|
|
}
|
|
|
|
/* read new layout */
|
|
romlayout = fopen(layout_fname, "r");
|
|
|
|
if (!romlayout) {
|
|
perror("Could not read layout file.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
while (!feof(romlayout)) {
|
|
char *tstr1, *tstr2;
|
|
|
|
if (2 != fscanf(romlayout, "%255s %255s\n", tempstr,
|
|
layout_region_name))
|
|
continue;
|
|
|
|
region_number = region_num(layout_region_name);
|
|
if (region_number < 0)
|
|
continue;
|
|
|
|
tstr1 = strtok(tempstr, ":");
|
|
tstr2 = strtok(NULL, ":");
|
|
if (!tstr1 || !tstr2) {
|
|
fprintf(stderr, "Could not parse layout file.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
new_regions[region_number].base = strtol(tstr1,
|
|
(char **)NULL, 16);
|
|
new_regions[region_number].limit = strtol(tstr2,
|
|
(char **)NULL, 16);
|
|
new_regions[region_number].size =
|
|
new_regions[region_number].limit -
|
|
new_regions[region_number].base + 1;
|
|
|
|
if (new_regions[region_number].size < 0)
|
|
new_regions[region_number].size = 0;
|
|
}
|
|
fclose(romlayout);
|
|
|
|
/* check new layout */
|
|
for (i = 0; i < MAX_REGIONS; i++) {
|
|
if (new_regions[i].size == 0)
|
|
continue;
|
|
|
|
if (new_regions[i].size < current_regions[i].size) {
|
|
printf("DANGER: Region %s is shrinking.\n",
|
|
region_name(i));
|
|
printf(" The region will be truncated to fit.\n");
|
|
printf(" This may result in an unusable image.\n");
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
/* detect if the image size should grow */
|
|
if (new_extent < new_regions[i].limit)
|
|
new_extent = new_regions[i].limit;
|
|
}
|
|
|
|
new_extent = next_pow2(new_extent - 1);
|
|
if (new_extent != size) {
|
|
printf("The image has changed in size.\n");
|
|
printf("The old image is %d bytes.\n", size);
|
|
printf("The new image is %d bytes.\n", new_extent);
|
|
}
|
|
|
|
/* copy regions to a new image */
|
|
new_image = malloc(new_extent);
|
|
memset(new_image, 0xff, new_extent);
|
|
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];
|
|
region_t new = new_regions[i];
|
|
|
|
if (new.size == 0)
|
|
continue;
|
|
|
|
if (new.size > current.size) {
|
|
/* copy from the end of the current region */
|
|
copy_size = current.size;
|
|
offset_new = new.size - current.size;
|
|
}
|
|
|
|
if (new.size < current.size) {
|
|
/* copy to the end of the new region */
|
|
offset_current = current.size - new.size;
|
|
}
|
|
|
|
printf("Copy Descriptor %d (%s) (%d bytes)\n", i,
|
|
region_name(i), copy_size);
|
|
printf(" from %08x+%08x:%08x (%10d)\n", current.base,
|
|
offset_current, current.limit, current.size);
|
|
printf(" to %08x+%08x:%08x (%10d)\n", new.base,
|
|
offset_new, new.limit, new.size);
|
|
|
|
memcpy(new_image + new.base + offset_new,
|
|
image + current.base + offset_current,
|
|
copy_size);
|
|
}
|
|
|
|
/* update new descriptor regions */
|
|
fdb = find_fd(new_image, new_extent);
|
|
if (!fdb)
|
|
exit(EXIT_FAILURE);
|
|
|
|
frba = (frba_t *) (new_image + (((fdb->flmap0 >> 16) & 0xff) << 4));
|
|
for (i = 1; i < MAX_REGIONS; i++) {
|
|
set_region(frba, i, new_regions[i]);
|
|
}
|
|
|
|
write_image(filename, new_image, new_extent);
|
|
free(new_image);
|
|
}
|
|
|
|
static void print_version(void)
|
|
{
|
|
printf("ifdtool v%s -- ", IFDTOOL_VERSION);
|
|
printf("Copyright (C) 2011 Google Inc.\n\n");
|
|
printf
|
|
("This program is free software: you can redistribute it and/or modify\n"
|
|
"it under the terms of the GNU General Public License as published by\n"
|
|
"the Free Software Foundation, version 2 of the License.\n\n"
|
|
"This program is distributed in the hope that it will be useful,\n"
|
|
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
|
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
|
"GNU General Public License for more details.\n\n"
|
|
"You should have received a copy of the GNU General Public License\n"
|
|
"along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n");
|
|
}
|
|
|
|
static void print_usage(const char *name)
|
|
{
|
|
printf("usage: %s [-vhdix?] <filename>\n", name);
|
|
printf("\n"
|
|
" -d | --dump: dump intel firmware descriptor\n"
|
|
" -f | --layout <filename> dump regions into a flashrom layout file\n"
|
|
" -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 <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"
|
|
" -u | --unlock Unlock firmware descriptor and ME region\n"
|
|
" -v | --version: print the version\n"
|
|
" -h | --help: print this help\n\n"
|
|
"<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
|
|
"\n");
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int opt, option_index = 0;
|
|
int mode_dump = 0, mode_extract = 0, mode_inject = 0, mode_spifreq = 0;
|
|
int mode_em100 = 0, mode_locked = 0, mode_unlocked = 0;
|
|
int mode_layout = 0, mode_newlayout = 0;
|
|
char *region_type_string = NULL, *region_fname = NULL, *layout_fname = NULL;
|
|
int region_type = -1, inputfreq = 0;
|
|
enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
|
|
|
|
static struct option long_options[] = {
|
|
{"dump", 0, NULL, 'd'},
|
|
{"layout", 1, NULL, 'f'},
|
|
{"extract", 0, NULL, 'x'},
|
|
{"inject", 1, NULL, 'i'},
|
|
{"newlayout", 1, NULL, 'n'},
|
|
{"spifreq", 1, NULL, 's'},
|
|
{"em100", 0, NULL, 'e'},
|
|
{"lock", 0, NULL, 'l'},
|
|
{"unlock", 0, NULL, 'u'},
|
|
{"version", 0, NULL, 'v'},
|
|
{"help", 0, NULL, 'h'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
while ((opt = getopt_long(argc, argv, "df:xi:n:s:eluvh?",
|
|
long_options, &option_index)) != EOF) {
|
|
switch (opt) {
|
|
case 'd':
|
|
mode_dump = 1;
|
|
break;
|
|
case 'f':
|
|
mode_layout = 1;
|
|
layout_fname = strdup(optarg);
|
|
if (!layout_fname) {
|
|
fprintf(stderr, "No layout file specified\n");
|
|
print_usage(argv[0]);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
break;
|
|
case 'x':
|
|
mode_extract = 1;
|
|
break;
|
|
case 'i':
|
|
// separate type and file name
|
|
region_type_string = strdup(optarg);
|
|
region_fname = strchr(region_type_string, ':');
|
|
if (!region_fname) {
|
|
print_usage(argv[0]);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
region_fname[0] = '\0';
|
|
region_fname++;
|
|
// Descriptor, BIOS, ME, GbE, Platform
|
|
// valid type?
|
|
if (!strcasecmp("Descriptor", region_type_string))
|
|
region_type = 0;
|
|
else if (!strcasecmp("BIOS", region_type_string))
|
|
region_type = 1;
|
|
else if (!strcasecmp("ME", region_type_string))
|
|
region_type = 2;
|
|
else if (!strcasecmp("GbE", region_type_string))
|
|
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);
|
|
print_usage(argv[0]);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
mode_inject = 1;
|
|
break;
|
|
case 'n':
|
|
mode_newlayout = 1;
|
|
layout_fname = strdup(optarg);
|
|
if (!layout_fname) {
|
|
fprintf(stderr, "No layout file specified\n");
|
|
print_usage(argv[0]);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
break;
|
|
case 's':
|
|
// 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_30MHZ;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "Invalid SPI Frequency: %d\n",
|
|
inputfreq);
|
|
print_usage(argv[0]);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
mode_spifreq = 1;
|
|
break;
|
|
case 'e':
|
|
mode_em100 = 1;
|
|
break;
|
|
case 'l':
|
|
mode_locked = 1;
|
|
if (mode_unlocked == 1) {
|
|
fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
break;
|
|
case 'u':
|
|
mode_unlocked = 1;
|
|
if (mode_locked == 1) {
|
|
fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
break;
|
|
case 'v':
|
|
print_version();
|
|
exit(EXIT_SUCCESS);
|
|
break;
|
|
case 'h':
|
|
case '?':
|
|
default:
|
|
print_usage(argv[0]);
|
|
exit(EXIT_SUCCESS);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((mode_dump + mode_layout + mode_extract + mode_inject +
|
|
mode_newlayout + (mode_spifreq | mode_em100 | mode_unlocked |
|
|
mode_locked)) > 1) {
|
|
fprintf(stderr, "You may not specify more than one mode.\n\n");
|
|
print_usage(argv[0]);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if ((mode_dump + mode_layout + mode_extract + mode_inject +
|
|
mode_newlayout + mode_spifreq + mode_em100 + mode_locked +
|
|
mode_unlocked) == 0) {
|
|
fprintf(stderr, "You need to specify a mode.\n\n");
|
|
print_usage(argv[0]);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (optind + 1 != argc) {
|
|
fprintf(stderr, "You need to specify a file.\n\n");
|
|
print_usage(argv[0]);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
char *filename = argv[optind];
|
|
int bios_fd = open(filename, O_RDONLY | O_BINARY);
|
|
if (bios_fd == -1) {
|
|
perror("Could not open file");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
struct stat buf;
|
|
if (fstat(bios_fd, &buf) == -1) {
|
|
perror("Could not stat file");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
int size = buf.st_size;
|
|
|
|
printf("File %s is %d bytes\n", filename, size);
|
|
|
|
char *image = malloc(size);
|
|
if (!image) {
|
|
printf("Out of memory.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (read(bios_fd, image, size) != size) {
|
|
perror("Could not read file");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
close(bios_fd);
|
|
|
|
check_ifd_version(image, size);
|
|
|
|
if (mode_dump)
|
|
dump_fd(image, size);
|
|
|
|
if (mode_layout)
|
|
dump_layout(image, size, layout_fname);
|
|
|
|
if (mode_extract)
|
|
write_regions(image, size);
|
|
|
|
if (mode_inject)
|
|
inject_region(filename, image, size, region_type,
|
|
region_fname);
|
|
|
|
if (mode_newlayout)
|
|
new_layout(filename, image, size, layout_fname);
|
|
|
|
if (mode_spifreq)
|
|
set_spi_frequency(filename, image, size, spifreq);
|
|
|
|
if (mode_em100)
|
|
set_em100_mode(filename, image, size);
|
|
|
|
if(mode_locked)
|
|
lock_descriptor(filename, image, size);
|
|
|
|
if (mode_unlocked)
|
|
unlock_descriptor(filename, image, size);
|
|
|
|
free(image);
|
|
|
|
return 0;
|
|
}
|