blob: 74c92727efc588515bf725e28b901ad3e166cf7d [file] [log] [blame]
Nico Huber413b0d92013-06-19 12:41:19 +02001/*
2 * ifdfake - Create an Intel Firmware Descriptor with just a section layout
3 *
4 * Copyright (C) 2013 secunet Security Networks AG
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Nico Huber413b0d92013-06-19 12:41:19 +020014 */
15
16#include <errno.h>
17#include <stdio.h>
18#include <stdint.h>
19#include <stdlib.h>
20#include <string.h>
21#include <getopt.h>
22
23#define FDBAR_OFFSET 0x10
24#define FRBA_OFFSET 0x40
25
26typedef struct {
27 uint32_t base, limit, size;
28} region_t;
29
30static void write_image(const region_t regions[], const char *const image)
31{
32 FILE *const f = fopen(image, "w");
33 if (!f) {
34 perror("Could not open file");
35 exit(EXIT_FAILURE);
36 }
37
38 if (fseek(f, 0x1000 - 1, SEEK_SET)) {
39 perror("Failed to seek to end of descriptor");
40 exit(EXIT_FAILURE);
41 }
42 char zero = '\0';
43 if (fwrite(&zero, 1, 1, f) != 1) {
44 fprintf(stderr, "Failed to write at end of descriptor.\n");
45 exit(EXIT_FAILURE);
46 }
47
48 if (fseek(f, FDBAR_OFFSET, SEEK_SET)) {
49 perror("Failed to seek to fdbar");
50 exit(EXIT_FAILURE);
51 }
52
53 struct {
54 uint32_t flvalsig;
55 uint32_t flmap0;
56 } fdbar;
57 memset(&fdbar, 0x00, sizeof(fdbar));
58 fdbar.flvalsig = 0x0ff0a55a;
59 fdbar.flmap0 = (FRBA_OFFSET >> 4) << 16;
60 if (fwrite(&fdbar, sizeof(fdbar), 1, f) != 1) {
61 fprintf(stderr, "Failed to write fdbar.\n");
62 exit(EXIT_FAILURE);
63 }
64
65 int i;
66 uint32_t frba[5];
67 for (i = 0; i < 5; ++i) {
68 if (regions[i].size)
69 frba[i] = ((regions[i].limit & 0xfff000) << (16 - 12)) |
70 ((regions[i].base & 0xfff000) >> 12);
71 else
72 frba[i] = 0x00000fff;
73 }
74
75 if (fseek(f, FRBA_OFFSET, SEEK_SET)) {
76 perror("Failed to seek to frba");
77 exit(EXIT_FAILURE);
78 }
79 if (fwrite(frba, sizeof(frba), 1, f) != 1) {
80 fprintf(stderr, "Failed to write frba.\n");
81 exit(EXIT_FAILURE);
82 }
83
84 fclose(f);
85}
86
87static int parse_region(const char *_arg, region_t *const region)
88{
89 char *const start = strdup(_arg);
Patrick Georgia9992d32015-09-11 13:48:24 +020090 int size_spec = 0;
91 unsigned long first, second;
Nico Huber413b0d92013-06-19 12:41:19 +020092 if (!start) {
93 fprintf(stderr, "Out of memory.\n");
94 exit(EXIT_FAILURE);
95 }
96
Patrick Georgia9992d32015-09-11 13:48:24 +020097 char *colon = strchr(start, ':');
Nico Huber413b0d92013-06-19 12:41:19 +020098 if (!colon) {
Patrick Georgia9992d32015-09-11 13:48:24 +020099 colon = strchr(start, '+');
100 if (!colon) {
101 free(start);
102 return -1;
103 }
104 size_spec = 1;
Nico Huber413b0d92013-06-19 12:41:19 +0200105 }
106 *colon = '\0';
107
108 char *const end = colon + 1;
109
110 errno = 0;
Patrick Georgia9992d32015-09-11 13:48:24 +0200111 first = strtoul(start, NULL, 0);
112 second = strtoul(end, NULL, 0);
113
114 if (size_spec) {
115 region->base = first;
116 region->size = second;
117 region->limit = region->base + region->size - 1;
118 } else {
119 region->base = first;
120 region->limit = second;
121 region->size = region->limit - region->base + 1;
122 }
Nico Huber413b0d92013-06-19 12:41:19 +0200123
124 free(start);
125 if (errno) {
126 perror("Failed to parse region");
127 return -1;
128 } else {
129 return 0;
130 }
131}
132
133static void print_usage(const char *name)
134{
135 printf("usage: %s [(-b|-m|-g|-p) <start>:<end>]... <output file>\n", name);
136 printf("\n"
137 " -b | --bios <start>:<end> BIOS region\n"
138 " -m | --me <start>:<end> Intel ME region\n"
139 " -g | --gbe <start>:<end> Gigabit Ethernet region\n"
140 " -p | --platform <start>:<end> Platform Data region\n"
141 " -h | --help print this help\n\n"
142 "<start> and <end> bounds are given in bytes, the <end> bound is inclusive.\n"
143 "All regions must be multiples of 4K in size and 4K aligned.\n"
144 "The descriptor region always resides in the first 4K.\n\n"
145 "An IFD created with ifdfake won't work as a replacement for a real IFD.\n"
146 "Never try to flash such an IFD to your board!\n\n");
147}
148
149int main(int argc, char *argv[])
150{
151 int opt, option_index = 0, idx;
152 region_t regions[5];
153
154 memset(regions, 0x00, sizeof(regions));
155
156 static struct option long_options[] = {
157 {"bios", 1, NULL, 'b'},
158 {"me", 1, NULL, 'm'},
159 {"gbe", 1, NULL, 'g'},
160 {"platform", 1, NULL, 'p'},
161 {"help", 0, NULL, 'h'},
162 {0, 0, 0, 0}
163 };
164
165 while ((opt = getopt_long(argc, argv, "b:m:g:p:h?",
166 long_options, &option_index)) != EOF) {
167 switch (opt) {
168 case 'b': case 'm': case 'g': case 'p':
169 switch (opt) {
170 case 'b': idx = 1; break;
171 case 'm': idx = 2; break;
172 case 'g': idx = 3; break;
173 case 'p': idx = 4; break;
174 default: idx = 0; break; /* can't happen */
175 }
176 if (parse_region(optarg, &regions[idx])) {
177 print_usage(argv[0]);
178 exit(EXIT_FAILURE);
179 }
180 break;
181 case 'h':
182 case '?':
183 default:
184 print_usage(argv[0]);
185 exit(EXIT_SUCCESS);
186 break;
187 }
188 }
189
190 if (optind + 1 != argc) {
191 fprintf(stderr, "No output file given.\n\n");
192 print_usage(argv[0]);
193 exit(EXIT_FAILURE);
194 }
195
196 regions[0].base = 0x00000000;
197 regions[0].limit = 0x00000fff;
198 regions[0].size = 0x00001000;
199 for (idx = 1; idx < 5; ++idx) {
200 if (regions[idx].size) {
201 if (regions[idx].base & 0xfff)
202 fprintf(stderr, "Region %d is "
203 "not 4K aligned.\n", idx);
204 else if (regions[idx].size & 0xfff)
205 fprintf(stderr, "Region %d size is "
206 "no multiple of 4K.\n", idx);
207 else if (regions[idx].limit <= regions[idx].base)
208 fprintf(stderr, "Region %d is empty.\n", idx);
209 else
210 continue;
211 print_usage(argv[0]);
212 exit(EXIT_FAILURE);
213 }
214 }
215
216 write_image(regions, argv[optind]);
217
218 return 0;
219}