blob: b549f3ad8d4623bcf6fb56edbf2e1d2491f581c2 [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
Nico Hubere70bfee2016-11-16 16:01:50 +010023#define REGION_COUNT 5
24
Nico Huber413b0d92013-06-19 12:41:19 +020025#define FDBAR_OFFSET 0x10
26#define FRBA_OFFSET 0x40
27
28typedef struct {
29 uint32_t base, limit, size;
30} region_t;
31
32static void write_image(const region_t regions[], const char *const image)
33{
34 FILE *const f = fopen(image, "w");
35 if (!f) {
36 perror("Could not open file");
37 exit(EXIT_FAILURE);
38 }
39
40 if (fseek(f, 0x1000 - 1, SEEK_SET)) {
41 perror("Failed to seek to end of descriptor");
42 exit(EXIT_FAILURE);
43 }
44 char zero = '\0';
45 if (fwrite(&zero, 1, 1, f) != 1) {
46 fprintf(stderr, "Failed to write at end of descriptor.\n");
47 exit(EXIT_FAILURE);
48 }
49
50 if (fseek(f, FDBAR_OFFSET, SEEK_SET)) {
51 perror("Failed to seek to fdbar");
52 exit(EXIT_FAILURE);
53 }
54
55 struct {
56 uint32_t flvalsig;
57 uint32_t flmap0;
58 } fdbar;
59 memset(&fdbar, 0x00, sizeof(fdbar));
60 fdbar.flvalsig = 0x0ff0a55a;
Nico Hubere70bfee2016-11-16 16:01:50 +010061 fdbar.flmap0 = (REGION_COUNT - 1) << 24 | (FRBA_OFFSET >> 4) << 16;
Nico Huber413b0d92013-06-19 12:41:19 +020062 if (fwrite(&fdbar, sizeof(fdbar), 1, f) != 1) {
63 fprintf(stderr, "Failed to write fdbar.\n");
64 exit(EXIT_FAILURE);
65 }
66
67 int i;
Nico Hubere70bfee2016-11-16 16:01:50 +010068 uint32_t frba[REGION_COUNT];
69 for (i = 0; i < REGION_COUNT; ++i) {
Nico Huber413b0d92013-06-19 12:41:19 +020070 if (regions[i].size)
71 frba[i] = ((regions[i].limit & 0xfff000) << (16 - 12)) |
72 ((regions[i].base & 0xfff000) >> 12);
73 else
74 frba[i] = 0x00000fff;
75 }
76
77 if (fseek(f, FRBA_OFFSET, SEEK_SET)) {
78 perror("Failed to seek to frba");
79 exit(EXIT_FAILURE);
80 }
81 if (fwrite(frba, sizeof(frba), 1, f) != 1) {
82 fprintf(stderr, "Failed to write frba.\n");
83 exit(EXIT_FAILURE);
84 }
85
86 fclose(f);
87}
88
89static int parse_region(const char *_arg, region_t *const region)
90{
91 char *const start = strdup(_arg);
Patrick Georgia9992d32015-09-11 13:48:24 +020092 int size_spec = 0;
93 unsigned long first, second;
Nico Huber413b0d92013-06-19 12:41:19 +020094 if (!start) {
95 fprintf(stderr, "Out of memory.\n");
96 exit(EXIT_FAILURE);
97 }
98
Patrick Georgia9992d32015-09-11 13:48:24 +020099 char *colon = strchr(start, ':');
Nico Huber413b0d92013-06-19 12:41:19 +0200100 if (!colon) {
Patrick Georgia9992d32015-09-11 13:48:24 +0200101 colon = strchr(start, '+');
102 if (!colon) {
103 free(start);
104 return -1;
105 }
106 size_spec = 1;
Nico Huber413b0d92013-06-19 12:41:19 +0200107 }
108 *colon = '\0';
109
110 char *const end = colon + 1;
111
112 errno = 0;
Patrick Georgia9992d32015-09-11 13:48:24 +0200113 first = strtoul(start, NULL, 0);
114 second = strtoul(end, NULL, 0);
115
116 if (size_spec) {
117 region->base = first;
118 region->size = second;
119 region->limit = region->base + region->size - 1;
120 } else {
121 region->base = first;
122 region->limit = second;
123 region->size = region->limit - region->base + 1;
124 }
Nico Huber413b0d92013-06-19 12:41:19 +0200125
126 free(start);
127 if (errno) {
128 perror("Failed to parse region");
129 return -1;
130 } else {
131 return 0;
132 }
133}
134
135static void print_usage(const char *name)
136{
137 printf("usage: %s [(-b|-m|-g|-p) <start>:<end>]... <output file>\n", name);
138 printf("\n"
139 " -b | --bios <start>:<end> BIOS region\n"
140 " -m | --me <start>:<end> Intel ME region\n"
141 " -g | --gbe <start>:<end> Gigabit Ethernet region\n"
142 " -p | --platform <start>:<end> Platform Data region\n"
143 " -h | --help print this help\n\n"
144 "<start> and <end> bounds are given in bytes, the <end> bound is inclusive.\n"
145 "All regions must be multiples of 4K in size and 4K aligned.\n"
146 "The descriptor region always resides in the first 4K.\n\n"
147 "An IFD created with ifdfake won't work as a replacement for a real IFD.\n"
148 "Never try to flash such an IFD to your board!\n\n");
149}
150
151int main(int argc, char *argv[])
152{
153 int opt, option_index = 0, idx;
Nico Hubere70bfee2016-11-16 16:01:50 +0100154 region_t regions[REGION_COUNT];
Nico Huber413b0d92013-06-19 12:41:19 +0200155
156 memset(regions, 0x00, sizeof(regions));
157
158 static struct option long_options[] = {
159 {"bios", 1, NULL, 'b'},
160 {"me", 1, NULL, 'm'},
161 {"gbe", 1, NULL, 'g'},
162 {"platform", 1, NULL, 'p'},
163 {"help", 0, NULL, 'h'},
164 {0, 0, 0, 0}
165 };
166
167 while ((opt = getopt_long(argc, argv, "b:m:g:p:h?",
168 long_options, &option_index)) != EOF) {
169 switch (opt) {
170 case 'b': case 'm': case 'g': case 'p':
171 switch (opt) {
172 case 'b': idx = 1; break;
173 case 'm': idx = 2; break;
174 case 'g': idx = 3; break;
175 case 'p': idx = 4; break;
176 default: idx = 0; break; /* can't happen */
177 }
178 if (parse_region(optarg, &regions[idx])) {
179 print_usage(argv[0]);
180 exit(EXIT_FAILURE);
181 }
182 break;
183 case 'h':
184 case '?':
185 default:
186 print_usage(argv[0]);
187 exit(EXIT_SUCCESS);
188 break;
189 }
190 }
191
192 if (optind + 1 != argc) {
193 fprintf(stderr, "No output file given.\n\n");
194 print_usage(argv[0]);
195 exit(EXIT_FAILURE);
196 }
197
198 regions[0].base = 0x00000000;
199 regions[0].limit = 0x00000fff;
200 regions[0].size = 0x00001000;
Nico Hubere70bfee2016-11-16 16:01:50 +0100201 for (idx = 1; idx < REGION_COUNT; ++idx) {
Nico Huber413b0d92013-06-19 12:41:19 +0200202 if (regions[idx].size) {
203 if (regions[idx].base & 0xfff)
204 fprintf(stderr, "Region %d is "
205 "not 4K aligned.\n", idx);
206 else if (regions[idx].size & 0xfff)
207 fprintf(stderr, "Region %d size is "
208 "no multiple of 4K.\n", idx);
209 else if (regions[idx].limit <= regions[idx].base)
210 fprintf(stderr, "Region %d is empty.\n", idx);
211 else
212 continue;
213 print_usage(argv[0]);
214 exit(EXIT_FAILURE);
215 }
216 }
217
218 write_image(regions, argv[optind]);
219
220 return 0;
221}