diff options
Diffstat (limited to 'util/ifdfake')
-rw-r--r-- | util/ifdfake/Makefile | 43 | ||||
-rw-r--r-- | util/ifdfake/ifdfake.c | 208 |
2 files changed, 251 insertions, 0 deletions
diff --git a/util/ifdfake/Makefile b/util/ifdfake/Makefile new file mode 100644 index 0000000000..3a896eeb09 --- /dev/null +++ b/util/ifdfake/Makefile @@ -0,0 +1,43 @@ +# +# ifdfake - Create an Intel Firmware Descriptor with just a section layout +# +# Copyright (C) 2013 secunet Security Networks AG +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA +# + +PROGRAM = ifdfake + +CC ?= gcc +INSTALL ?= /usr/bin/install +PREFIX ?= /usr/local +CFLAGS ?= -O2 -g -Wall -W + +OBJS = ifdfake.o + +all: $(PROGRAM) + +$(PROGRAM): $(OBJS) + $(CC) -o $(PROGRAM) $(OBJS) $(LDFLAGS) + +clean: + rm -f $(PROGRAM) *.o *~ + +distclean: clean + +install: $(PROGRAM) + mkdir -p $(DESTDIR)$(PREFIX)/bin + $(INSTALL) $(PROGRAM) $(DESTDIR)$(PREFIX)/bin + +.PHONY: all clean distclean diff --git a/util/ifdfake/ifdfake.c b/util/ifdfake/ifdfake.c new file mode 100644 index 0000000000..8eb34a9972 --- /dev/null +++ b/util/ifdfake/ifdfake.c @@ -0,0 +1,208 @@ +/* + * ifdfake - Create an Intel Firmware Descriptor with just a section layout + * + * Copyright (C) 2013 secunet Security Networks AG + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + */ + +#include <errno.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> + +#define FDBAR_OFFSET 0x10 +#define FRBA_OFFSET 0x40 + +typedef struct { + uint32_t base, limit, size; +} region_t; + +static void write_image(const region_t regions[], const char *const image) +{ + FILE *const f = fopen(image, "w"); + if (!f) { + perror("Could not open file"); + exit(EXIT_FAILURE); + } + + if (fseek(f, 0x1000 - 1, SEEK_SET)) { + perror("Failed to seek to end of descriptor"); + exit(EXIT_FAILURE); + } + char zero = '\0'; + if (fwrite(&zero, 1, 1, f) != 1) { + fprintf(stderr, "Failed to write at end of descriptor.\n"); + exit(EXIT_FAILURE); + } + + if (fseek(f, FDBAR_OFFSET, SEEK_SET)) { + perror("Failed to seek to fdbar"); + exit(EXIT_FAILURE); + } + + struct { + uint32_t flvalsig; + uint32_t flmap0; + } fdbar; + memset(&fdbar, 0x00, sizeof(fdbar)); + fdbar.flvalsig = 0x0ff0a55a; + fdbar.flmap0 = (FRBA_OFFSET >> 4) << 16; + if (fwrite(&fdbar, sizeof(fdbar), 1, f) != 1) { + fprintf(stderr, "Failed to write fdbar.\n"); + exit(EXIT_FAILURE); + } + + int i; + uint32_t frba[5]; + for (i = 0; i < 5; ++i) { + if (regions[i].size) + frba[i] = ((regions[i].limit & 0xfff000) << (16 - 12)) | + ((regions[i].base & 0xfff000) >> 12); + else + frba[i] = 0x00000fff; + } + + if (fseek(f, FRBA_OFFSET, SEEK_SET)) { + perror("Failed to seek to frba"); + exit(EXIT_FAILURE); + } + if (fwrite(frba, sizeof(frba), 1, f) != 1) { + fprintf(stderr, "Failed to write frba.\n"); + exit(EXIT_FAILURE); + } + + fclose(f); +} + +static int parse_region(const char *_arg, region_t *const region) +{ + char *const start = strdup(_arg); + if (!start) { + fprintf(stderr, "Out of memory.\n"); + exit(EXIT_FAILURE); + } + + char *const colon = strchr(start, ':'); + if (!colon) { + free(start); + return -1; + } + *colon = '\0'; + + char *const end = colon + 1; + + errno = 0; + region->base = strtoul(start, NULL, 0); + region->limit = strtoul(end, NULL, 0); + region->size = region->limit - region->base + 1; + + free(start); + if (errno) { + perror("Failed to parse region"); + return -1; + } else { + return 0; + } +} + +static void print_usage(const char *name) +{ + printf("usage: %s [(-b|-m|-g|-p) <start>:<end>]... <output file>\n", name); + printf("\n" + " -b | --bios <start>:<end> BIOS region\n" + " -m | --me <start>:<end> Intel ME region\n" + " -g | --gbe <start>:<end> Gigabit Ethernet region\n" + " -p | --platform <start>:<end> Platform Data region\n" + " -h | --help print this help\n\n" + "<start> and <end> bounds are given in bytes, the <end> bound is inclusive.\n" + "All regions must be multiples of 4K in size and 4K aligned.\n" + "The descriptor region always resides in the first 4K.\n\n" + "An IFD created with ifdfake won't work as a replacement for a real IFD.\n" + "Never try to flash such an IFD to your board!\n\n"); +} + +int main(int argc, char *argv[]) +{ + int opt, option_index = 0, idx; + region_t regions[5]; + + memset(regions, 0x00, sizeof(regions)); + + static struct option long_options[] = { + {"bios", 1, NULL, 'b'}, + {"me", 1, NULL, 'm'}, + {"gbe", 1, NULL, 'g'}, + {"platform", 1, NULL, 'p'}, + {"help", 0, NULL, 'h'}, + {0, 0, 0, 0} + }; + + while ((opt = getopt_long(argc, argv, "b:m:g:p:h?", + long_options, &option_index)) != EOF) { + switch (opt) { + case 'b': case 'm': case 'g': case 'p': + switch (opt) { + case 'b': idx = 1; break; + case 'm': idx = 2; break; + case 'g': idx = 3; break; + case 'p': idx = 4; break; + default: idx = 0; break; /* can't happen */ + } + if (parse_region(optarg, ®ions[idx])) { + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + break; + case 'h': + case '?': + default: + print_usage(argv[0]); + exit(EXIT_SUCCESS); + break; + } + } + + if (optind + 1 != argc) { + fprintf(stderr, "No output file given.\n\n"); + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + + regions[0].base = 0x00000000; + regions[0].limit = 0x00000fff; + regions[0].size = 0x00001000; + for (idx = 1; idx < 5; ++idx) { + if (regions[idx].size) { + if (regions[idx].base & 0xfff) + fprintf(stderr, "Region %d is " + "not 4K aligned.\n", idx); + else if (regions[idx].size & 0xfff) + fprintf(stderr, "Region %d size is " + "no multiple of 4K.\n", idx); + else if (regions[idx].limit <= regions[idx].base) + fprintf(stderr, "Region %d is empty.\n", idx); + else + continue; + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + } + + write_image(regions, argv[optind]); + + return 0; +} |