mirror of
https://github.com/fail0verflow/switch-coreboot.git
synced 2025-05-04 01:39:18 -04:00
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>
1264 lines
34 KiB
C
1264 lines
34 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc.
|
|
*/
|
|
|
|
#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)
|
|
{
|
|
region_t region;
|
|
region.base = 0, region.limit = 0, region.size = 0;
|
|
|
|
switch (region_type) {
|
|
case 0:
|
|
region.base = (frba->flreg0 & 0x00000fff) << 12;
|
|
region.limit = ((frba->flreg0 & 0x0fff0000) >> 4) | 0xfff;
|
|
break;
|
|
case 1:
|
|
region.base = (frba->flreg1 & 0x00000fff) << 12;
|
|
region.limit = ((frba->flreg1 & 0x0fff0000) >> 4) | 0xfff;
|
|
break;
|
|
case 2:
|
|
region.base = (frba->flreg2 & 0x00000fff) << 12;
|
|
region.limit = ((frba->flreg2 & 0x0fff0000) >> 4) | 0xfff;
|
|
break;
|
|
case 3:
|
|
region.base = (frba->flreg3 & 0x00000fff) << 12;
|
|
region.limit = ((frba->flreg3 & 0x0fff0000) >> 4) | 0xfff;
|
|
break;
|
|
case 4:
|
|
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 %d.\n", region_type);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
|
|
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)
|
|
{
|
|
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",
|
|
(flmstr & (1 << 27)) ? "enabled" : "disabled");
|
|
printf(" Intel ME Region Write Access: %s\n",
|
|
(flmstr & (1 << 26)) ? "enabled" : "disabled");
|
|
printf(" Host CPU/BIOS Region Write Access: %s\n",
|
|
(flmstr & (1 << 25)) ? "enabled" : "disabled");
|
|
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",
|
|
(flmstr & (1 << 19)) ? "enabled" : "disabled");
|
|
printf(" Intel ME Region Read Access: %s\n",
|
|
(flmstr & (1 << 18)) ? "enabled" : "disabled");
|
|
printf(" Host CPU/BIOS Region Read Access: %s\n",
|
|
(flmstr & (1 << 17)) ? "enabled" : "disabled");
|
|
printf(" Flash Descriptor Read Access: %s\n",
|
|
(flmstr & (1 << 16)) ? "enabled" : "disabled");
|
|
|
|
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;
|
|
}
|
|
|
|
fcba->flcomp &= ~(1 << 30);
|
|
set_spi_frequency(filename, image, size, freq);
|
|
}
|
|
|
|
static void lock_descriptor(char *filename, char *image, int size)
|
|
{
|
|
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.
|
|
*/
|
|
fmba->flmstr1 = 0x0a0b0000;
|
|
fmba->flmstr2 = 0x0c0d0000;
|
|
fmba->flmstr3 = 0x08080118;
|
|
|
|
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));
|
|
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;
|
|
}
|