1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * ifdtool - Manage Intel Firmware Descriptor information
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright 2014 Google, Inc
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * From Coreboot project, but it got a serious code clean-up
9*4882a593Smuzhiyun * and a few new features
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <assert.h>
13*4882a593Smuzhiyun #include <fcntl.h>
14*4882a593Smuzhiyun #include <getopt.h>
15*4882a593Smuzhiyun #include <stdbool.h>
16*4882a593Smuzhiyun #include <stdlib.h>
17*4882a593Smuzhiyun #include <stdio.h>
18*4882a593Smuzhiyun #include <string.h>
19*4882a593Smuzhiyun #include <unistd.h>
20*4882a593Smuzhiyun #include <sys/types.h>
21*4882a593Smuzhiyun #include <sys/stat.h>
22*4882a593Smuzhiyun #include <linux/libfdt.h>
23*4882a593Smuzhiyun #include "ifdtool.h"
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #undef DEBUG
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #ifdef DEBUG
28*4882a593Smuzhiyun #define debug(fmt, args...) printf(fmt, ##args)
29*4882a593Smuzhiyun #else
30*4882a593Smuzhiyun #define debug(fmt, args...)
31*4882a593Smuzhiyun #endif
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define FD_SIGNATURE 0x0FF0A55A
34*4882a593Smuzhiyun #define FLREG_BASE(reg) ((reg & 0x00000fff) << 12);
35*4882a593Smuzhiyun #define FLREG_LIMIT(reg) (((reg & 0x0fff0000) >> 4) | 0xfff);
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun struct input_file {
38*4882a593Smuzhiyun char *fname;
39*4882a593Smuzhiyun unsigned int addr;
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /**
43*4882a593Smuzhiyun * find_fd() - Find the flash description in the ROM image
44*4882a593Smuzhiyun *
45*4882a593Smuzhiyun * @image: Pointer to image
46*4882a593Smuzhiyun * @size: Size of image in bytes
47*4882a593Smuzhiyun * @return pointer to structure, or NULL if not found
48*4882a593Smuzhiyun */
find_fd(char * image,int size)49*4882a593Smuzhiyun static struct fdbar_t *find_fd(char *image, int size)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun uint32_t *ptr, *end;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /* Scan for FD signature */
54*4882a593Smuzhiyun for (ptr = (uint32_t *)image, end = ptr + size / 4; ptr < end; ptr++) {
55*4882a593Smuzhiyun if (*ptr == FD_SIGNATURE)
56*4882a593Smuzhiyun break;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun if (ptr == end) {
60*4882a593Smuzhiyun printf("No Flash Descriptor found in this image\n");
61*4882a593Smuzhiyun return NULL;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun debug("Found Flash Descriptor signature at 0x%08lx\n",
65*4882a593Smuzhiyun (char *)ptr - image);
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun return (struct fdbar_t *)ptr;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /**
71*4882a593Smuzhiyun * get_region() - Get information about the selected region
72*4882a593Smuzhiyun *
73*4882a593Smuzhiyun * @frba: Flash region list
74*4882a593Smuzhiyun * @region_type: Type of region (0..MAX_REGIONS-1)
75*4882a593Smuzhiyun * @region: Region information is written here
76*4882a593Smuzhiyun * @return 0 if OK, else -ve
77*4882a593Smuzhiyun */
get_region(struct frba_t * frba,int region_type,struct region_t * region)78*4882a593Smuzhiyun static int get_region(struct frba_t *frba, int region_type,
79*4882a593Smuzhiyun struct region_t *region)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun if (region_type >= MAX_REGIONS) {
82*4882a593Smuzhiyun fprintf(stderr, "Invalid region type.\n");
83*4882a593Smuzhiyun return -1;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun region->base = FLREG_BASE(frba->flreg[region_type]);
87*4882a593Smuzhiyun region->limit = FLREG_LIMIT(frba->flreg[region_type]);
88*4882a593Smuzhiyun region->size = region->limit - region->base + 1;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun return 0;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
region_name(int region_type)93*4882a593Smuzhiyun static const char *region_name(int region_type)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun static const char *const regions[] = {
96*4882a593Smuzhiyun "Flash Descriptor",
97*4882a593Smuzhiyun "BIOS",
98*4882a593Smuzhiyun "Intel ME",
99*4882a593Smuzhiyun "GbE",
100*4882a593Smuzhiyun "Platform Data"
101*4882a593Smuzhiyun };
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun assert(region_type < MAX_REGIONS);
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun return regions[region_type];
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
region_filename(int region_type)108*4882a593Smuzhiyun static const char *region_filename(int region_type)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun static const char *const region_filenames[] = {
111*4882a593Smuzhiyun "flashregion_0_flashdescriptor.bin",
112*4882a593Smuzhiyun "flashregion_1_bios.bin",
113*4882a593Smuzhiyun "flashregion_2_intel_me.bin",
114*4882a593Smuzhiyun "flashregion_3_gbe.bin",
115*4882a593Smuzhiyun "flashregion_4_platform_data.bin"
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun assert(region_type < MAX_REGIONS);
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun return region_filenames[region_type];
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
dump_region(int num,struct frba_t * frba)123*4882a593Smuzhiyun static int dump_region(int num, struct frba_t *frba)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun struct region_t region;
126*4882a593Smuzhiyun int ret;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun ret = get_region(frba, num, ®ion);
129*4882a593Smuzhiyun if (ret)
130*4882a593Smuzhiyun return ret;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun printf(" Flash Region %d (%s): %08x - %08x %s\n",
133*4882a593Smuzhiyun num, region_name(num), region.base, region.limit,
134*4882a593Smuzhiyun region.size < 1 ? "(unused)" : "");
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun return ret;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
dump_frba(struct frba_t * frba)139*4882a593Smuzhiyun static void dump_frba(struct frba_t *frba)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun int i;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun printf("Found Region Section\n");
144*4882a593Smuzhiyun for (i = 0; i < MAX_REGIONS; i++) {
145*4882a593Smuzhiyun printf("FLREG%d: 0x%08x\n", i, frba->flreg[i]);
146*4882a593Smuzhiyun dump_region(i, frba);
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
decode_spi_frequency(unsigned int freq)150*4882a593Smuzhiyun static void decode_spi_frequency(unsigned int freq)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun switch (freq) {
153*4882a593Smuzhiyun case SPI_FREQUENCY_20MHZ:
154*4882a593Smuzhiyun printf("20MHz");
155*4882a593Smuzhiyun break;
156*4882a593Smuzhiyun case SPI_FREQUENCY_33MHZ:
157*4882a593Smuzhiyun printf("33MHz");
158*4882a593Smuzhiyun break;
159*4882a593Smuzhiyun case SPI_FREQUENCY_50MHZ:
160*4882a593Smuzhiyun printf("50MHz");
161*4882a593Smuzhiyun break;
162*4882a593Smuzhiyun default:
163*4882a593Smuzhiyun printf("unknown<%x>MHz", freq);
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
decode_component_density(unsigned int density)167*4882a593Smuzhiyun static void decode_component_density(unsigned int density)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun switch (density) {
170*4882a593Smuzhiyun case COMPONENT_DENSITY_512KB:
171*4882a593Smuzhiyun printf("512KiB");
172*4882a593Smuzhiyun break;
173*4882a593Smuzhiyun case COMPONENT_DENSITY_1MB:
174*4882a593Smuzhiyun printf("1MiB");
175*4882a593Smuzhiyun break;
176*4882a593Smuzhiyun case COMPONENT_DENSITY_2MB:
177*4882a593Smuzhiyun printf("2MiB");
178*4882a593Smuzhiyun break;
179*4882a593Smuzhiyun case COMPONENT_DENSITY_4MB:
180*4882a593Smuzhiyun printf("4MiB");
181*4882a593Smuzhiyun break;
182*4882a593Smuzhiyun case COMPONENT_DENSITY_8MB:
183*4882a593Smuzhiyun printf("8MiB");
184*4882a593Smuzhiyun break;
185*4882a593Smuzhiyun case COMPONENT_DENSITY_16MB:
186*4882a593Smuzhiyun printf("16MiB");
187*4882a593Smuzhiyun break;
188*4882a593Smuzhiyun default:
189*4882a593Smuzhiyun printf("unknown<%x>MiB", density);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
dump_fcba(struct fcba_t * fcba)193*4882a593Smuzhiyun static void dump_fcba(struct fcba_t *fcba)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun printf("\nFound Component Section\n");
196*4882a593Smuzhiyun printf("FLCOMP 0x%08x\n", fcba->flcomp);
197*4882a593Smuzhiyun printf(" Dual Output Fast Read Support: %ssupported\n",
198*4882a593Smuzhiyun (fcba->flcomp & (1 << 30)) ? "" : "not ");
199*4882a593Smuzhiyun printf(" Read ID/Read Status Clock Frequency: ");
200*4882a593Smuzhiyun decode_spi_frequency((fcba->flcomp >> 27) & 7);
201*4882a593Smuzhiyun printf("\n Write/Erase Clock Frequency: ");
202*4882a593Smuzhiyun decode_spi_frequency((fcba->flcomp >> 24) & 7);
203*4882a593Smuzhiyun printf("\n Fast Read Clock Frequency: ");
204*4882a593Smuzhiyun decode_spi_frequency((fcba->flcomp >> 21) & 7);
205*4882a593Smuzhiyun printf("\n Fast Read Support: %ssupported",
206*4882a593Smuzhiyun (fcba->flcomp & (1 << 20)) ? "" : "not ");
207*4882a593Smuzhiyun printf("\n Read Clock Frequency: ");
208*4882a593Smuzhiyun decode_spi_frequency((fcba->flcomp >> 17) & 7);
209*4882a593Smuzhiyun printf("\n Component 2 Density: ");
210*4882a593Smuzhiyun decode_component_density((fcba->flcomp >> 3) & 7);
211*4882a593Smuzhiyun printf("\n Component 1 Density: ");
212*4882a593Smuzhiyun decode_component_density(fcba->flcomp & 7);
213*4882a593Smuzhiyun printf("\n");
214*4882a593Smuzhiyun printf("FLILL 0x%08x\n", fcba->flill);
215*4882a593Smuzhiyun printf(" Invalid Instruction 3: 0x%02x\n",
216*4882a593Smuzhiyun (fcba->flill >> 24) & 0xff);
217*4882a593Smuzhiyun printf(" Invalid Instruction 2: 0x%02x\n",
218*4882a593Smuzhiyun (fcba->flill >> 16) & 0xff);
219*4882a593Smuzhiyun printf(" Invalid Instruction 1: 0x%02x\n",
220*4882a593Smuzhiyun (fcba->flill >> 8) & 0xff);
221*4882a593Smuzhiyun printf(" Invalid Instruction 0: 0x%02x\n",
222*4882a593Smuzhiyun fcba->flill & 0xff);
223*4882a593Smuzhiyun printf("FLPB 0x%08x\n", fcba->flpb);
224*4882a593Smuzhiyun printf(" Flash Partition Boundary Address: 0x%06x\n\n",
225*4882a593Smuzhiyun (fcba->flpb & 0xfff) << 12);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
dump_fpsba(struct fpsba_t * fpsba)228*4882a593Smuzhiyun static void dump_fpsba(struct fpsba_t *fpsba)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun int i;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun printf("Found PCH Strap Section\n");
233*4882a593Smuzhiyun for (i = 0; i < MAX_STRAPS; i++)
234*4882a593Smuzhiyun printf("PCHSTRP%-2d: 0x%08x\n", i, fpsba->pchstrp[i]);
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
get_enabled(int flag)237*4882a593Smuzhiyun static const char *get_enabled(int flag)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun return flag ? "enabled" : "disabled";
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
decode_flmstr(uint32_t flmstr)242*4882a593Smuzhiyun static void decode_flmstr(uint32_t flmstr)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun printf(" Platform Data Region Write Access: %s\n",
245*4882a593Smuzhiyun get_enabled(flmstr & (1 << 28)));
246*4882a593Smuzhiyun printf(" GbE Region Write Access: %s\n",
247*4882a593Smuzhiyun get_enabled(flmstr & (1 << 27)));
248*4882a593Smuzhiyun printf(" Intel ME Region Write Access: %s\n",
249*4882a593Smuzhiyun get_enabled(flmstr & (1 << 26)));
250*4882a593Smuzhiyun printf(" Host CPU/BIOS Region Write Access: %s\n",
251*4882a593Smuzhiyun get_enabled(flmstr & (1 << 25)));
252*4882a593Smuzhiyun printf(" Flash Descriptor Write Access: %s\n",
253*4882a593Smuzhiyun get_enabled(flmstr & (1 << 24)));
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun printf(" Platform Data Region Read Access: %s\n",
256*4882a593Smuzhiyun get_enabled(flmstr & (1 << 20)));
257*4882a593Smuzhiyun printf(" GbE Region Read Access: %s\n",
258*4882a593Smuzhiyun get_enabled(flmstr & (1 << 19)));
259*4882a593Smuzhiyun printf(" Intel ME Region Read Access: %s\n",
260*4882a593Smuzhiyun get_enabled(flmstr & (1 << 18)));
261*4882a593Smuzhiyun printf(" Host CPU/BIOS Region Read Access: %s\n",
262*4882a593Smuzhiyun get_enabled(flmstr & (1 << 17)));
263*4882a593Smuzhiyun printf(" Flash Descriptor Read Access: %s\n",
264*4882a593Smuzhiyun get_enabled(flmstr & (1 << 16)));
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun printf(" Requester ID: 0x%04x\n\n",
267*4882a593Smuzhiyun flmstr & 0xffff);
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
dump_fmba(struct fmba_t * fmba)270*4882a593Smuzhiyun static void dump_fmba(struct fmba_t *fmba)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun printf("Found Master Section\n");
273*4882a593Smuzhiyun printf("FLMSTR1: 0x%08x (Host CPU/BIOS)\n", fmba->flmstr1);
274*4882a593Smuzhiyun decode_flmstr(fmba->flmstr1);
275*4882a593Smuzhiyun printf("FLMSTR2: 0x%08x (Intel ME)\n", fmba->flmstr2);
276*4882a593Smuzhiyun decode_flmstr(fmba->flmstr2);
277*4882a593Smuzhiyun printf("FLMSTR3: 0x%08x (GbE)\n", fmba->flmstr3);
278*4882a593Smuzhiyun decode_flmstr(fmba->flmstr3);
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
dump_fmsba(struct fmsba_t * fmsba)281*4882a593Smuzhiyun static void dump_fmsba(struct fmsba_t *fmsba)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun int i;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun printf("Found Processor Strap Section\n");
286*4882a593Smuzhiyun for (i = 0; i < 4; i++)
287*4882a593Smuzhiyun printf("????: 0x%08x\n", fmsba->data[0]);
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
dump_jid(uint32_t jid)290*4882a593Smuzhiyun static void dump_jid(uint32_t jid)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun printf(" SPI Component Device ID 1: 0x%02x\n",
293*4882a593Smuzhiyun (jid >> 16) & 0xff);
294*4882a593Smuzhiyun printf(" SPI Component Device ID 0: 0x%02x\n",
295*4882a593Smuzhiyun (jid >> 8) & 0xff);
296*4882a593Smuzhiyun printf(" SPI Component Vendor ID: 0x%02x\n",
297*4882a593Smuzhiyun jid & 0xff);
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
dump_vscc(uint32_t vscc)300*4882a593Smuzhiyun static void dump_vscc(uint32_t vscc)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun printf(" Lower Erase Opcode: 0x%02x\n",
303*4882a593Smuzhiyun vscc >> 24);
304*4882a593Smuzhiyun printf(" Lower Write Enable on Write Status: 0x%02x\n",
305*4882a593Smuzhiyun vscc & (1 << 20) ? 0x06 : 0x50);
306*4882a593Smuzhiyun printf(" Lower Write Status Required: %s\n",
307*4882a593Smuzhiyun vscc & (1 << 19) ? "Yes" : "No");
308*4882a593Smuzhiyun printf(" Lower Write Granularity: %d bytes\n",
309*4882a593Smuzhiyun vscc & (1 << 18) ? 64 : 1);
310*4882a593Smuzhiyun printf(" Lower Block / Sector Erase Size: ");
311*4882a593Smuzhiyun switch ((vscc >> 16) & 0x3) {
312*4882a593Smuzhiyun case 0:
313*4882a593Smuzhiyun printf("256 Byte\n");
314*4882a593Smuzhiyun break;
315*4882a593Smuzhiyun case 1:
316*4882a593Smuzhiyun printf("4KB\n");
317*4882a593Smuzhiyun break;
318*4882a593Smuzhiyun case 2:
319*4882a593Smuzhiyun printf("8KB\n");
320*4882a593Smuzhiyun break;
321*4882a593Smuzhiyun case 3:
322*4882a593Smuzhiyun printf("64KB\n");
323*4882a593Smuzhiyun break;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun printf(" Upper Erase Opcode: 0x%02x\n",
327*4882a593Smuzhiyun (vscc >> 8) & 0xff);
328*4882a593Smuzhiyun printf(" Upper Write Enable on Write Status: 0x%02x\n",
329*4882a593Smuzhiyun vscc & (1 << 4) ? 0x06 : 0x50);
330*4882a593Smuzhiyun printf(" Upper Write Status Required: %s\n",
331*4882a593Smuzhiyun vscc & (1 << 3) ? "Yes" : "No");
332*4882a593Smuzhiyun printf(" Upper Write Granularity: %d bytes\n",
333*4882a593Smuzhiyun vscc & (1 << 2) ? 64 : 1);
334*4882a593Smuzhiyun printf(" Upper Block / Sector Erase Size: ");
335*4882a593Smuzhiyun switch (vscc & 0x3) {
336*4882a593Smuzhiyun case 0:
337*4882a593Smuzhiyun printf("256 Byte\n");
338*4882a593Smuzhiyun break;
339*4882a593Smuzhiyun case 1:
340*4882a593Smuzhiyun printf("4KB\n");
341*4882a593Smuzhiyun break;
342*4882a593Smuzhiyun case 2:
343*4882a593Smuzhiyun printf("8KB\n");
344*4882a593Smuzhiyun break;
345*4882a593Smuzhiyun case 3:
346*4882a593Smuzhiyun printf("64KB\n");
347*4882a593Smuzhiyun break;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
dump_vtba(struct vtba_t * vtba,int vtl)351*4882a593Smuzhiyun static void dump_vtba(struct vtba_t *vtba, int vtl)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun int i;
354*4882a593Smuzhiyun int num = (vtl >> 1) < 8 ? (vtl >> 1) : 8;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun printf("ME VSCC table:\n");
357*4882a593Smuzhiyun for (i = 0; i < num; i++) {
358*4882a593Smuzhiyun printf(" JID%d: 0x%08x\n", i, vtba->entry[i].jid);
359*4882a593Smuzhiyun dump_jid(vtba->entry[i].jid);
360*4882a593Smuzhiyun printf(" VSCC%d: 0x%08x\n", i, vtba->entry[i].vscc);
361*4882a593Smuzhiyun dump_vscc(vtba->entry[i].vscc);
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun printf("\n");
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
dump_oem(uint8_t * oem)366*4882a593Smuzhiyun static void dump_oem(uint8_t *oem)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun int i, j;
369*4882a593Smuzhiyun printf("OEM Section:\n");
370*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
371*4882a593Smuzhiyun printf("%02x:", i << 4);
372*4882a593Smuzhiyun for (j = 0; j < 16; j++)
373*4882a593Smuzhiyun printf(" %02x", oem[(i<<4)+j]);
374*4882a593Smuzhiyun printf("\n");
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun printf("\n");
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun /**
380*4882a593Smuzhiyun * dump_fd() - Display a dump of the full flash description
381*4882a593Smuzhiyun *
382*4882a593Smuzhiyun * @image: Pointer to image
383*4882a593Smuzhiyun * @size: Size of image in bytes
384*4882a593Smuzhiyun * @return 0 if OK, -1 on error
385*4882a593Smuzhiyun */
dump_fd(char * image,int size)386*4882a593Smuzhiyun static int dump_fd(char *image, int size)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun struct fdbar_t *fdb = find_fd(image, size);
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun if (!fdb)
391*4882a593Smuzhiyun return -1;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun printf("FLMAP0: 0x%08x\n", fdb->flmap0);
394*4882a593Smuzhiyun printf(" NR: %d\n", (fdb->flmap0 >> 24) & 7);
395*4882a593Smuzhiyun printf(" FRBA: 0x%x\n", ((fdb->flmap0 >> 16) & 0xff) << 4);
396*4882a593Smuzhiyun printf(" NC: %d\n", ((fdb->flmap0 >> 8) & 3) + 1);
397*4882a593Smuzhiyun printf(" FCBA: 0x%x\n", ((fdb->flmap0) & 0xff) << 4);
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun printf("FLMAP1: 0x%08x\n", fdb->flmap1);
400*4882a593Smuzhiyun printf(" ISL: 0x%02x\n", (fdb->flmap1 >> 24) & 0xff);
401*4882a593Smuzhiyun printf(" FPSBA: 0x%x\n", ((fdb->flmap1 >> 16) & 0xff) << 4);
402*4882a593Smuzhiyun printf(" NM: %d\n", (fdb->flmap1 >> 8) & 3);
403*4882a593Smuzhiyun printf(" FMBA: 0x%x\n", ((fdb->flmap1) & 0xff) << 4);
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun printf("FLMAP2: 0x%08x\n", fdb->flmap2);
406*4882a593Smuzhiyun printf(" PSL: 0x%04x\n", (fdb->flmap2 >> 8) & 0xffff);
407*4882a593Smuzhiyun printf(" FMSBA: 0x%x\n", ((fdb->flmap2) & 0xff) << 4);
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun printf("FLUMAP1: 0x%08x\n", fdb->flumap1);
410*4882a593Smuzhiyun printf(" Intel ME VSCC Table Length (VTL): %d\n",
411*4882a593Smuzhiyun (fdb->flumap1 >> 8) & 0xff);
412*4882a593Smuzhiyun printf(" Intel ME VSCC Table Base Address (VTBA): 0x%06x\n\n",
413*4882a593Smuzhiyun (fdb->flumap1 & 0xff) << 4);
414*4882a593Smuzhiyun dump_vtba((struct vtba_t *)
415*4882a593Smuzhiyun (image + ((fdb->flumap1 & 0xff) << 4)),
416*4882a593Smuzhiyun (fdb->flumap1 >> 8) & 0xff);
417*4882a593Smuzhiyun dump_oem((uint8_t *)image + 0xf00);
418*4882a593Smuzhiyun dump_frba((struct frba_t *)(image + (((fdb->flmap0 >> 16) & 0xff)
419*4882a593Smuzhiyun << 4)));
420*4882a593Smuzhiyun dump_fcba((struct fcba_t *)(image + (((fdb->flmap0) & 0xff) << 4)));
421*4882a593Smuzhiyun dump_fpsba((struct fpsba_t *)
422*4882a593Smuzhiyun (image + (((fdb->flmap1 >> 16) & 0xff) << 4)));
423*4882a593Smuzhiyun dump_fmba((struct fmba_t *)(image + (((fdb->flmap1) & 0xff) << 4)));
424*4882a593Smuzhiyun dump_fmsba((struct fmsba_t *)(image + (((fdb->flmap2) & 0xff) << 4)));
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun return 0;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun /**
430*4882a593Smuzhiyun * write_regions() - Write each region from an image to its own file
431*4882a593Smuzhiyun *
432*4882a593Smuzhiyun * The filename to use in each case is fixed - see region_filename()
433*4882a593Smuzhiyun *
434*4882a593Smuzhiyun * @image: Pointer to image
435*4882a593Smuzhiyun * @size: Size of image in bytes
436*4882a593Smuzhiyun * @return 0 if OK, -ve on error
437*4882a593Smuzhiyun */
write_regions(char * image,int size)438*4882a593Smuzhiyun static int write_regions(char *image, int size)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun struct fdbar_t *fdb;
441*4882a593Smuzhiyun struct frba_t *frba;
442*4882a593Smuzhiyun int ret = 0;
443*4882a593Smuzhiyun int i;
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun fdb = find_fd(image, size);
446*4882a593Smuzhiyun if (!fdb)
447*4882a593Smuzhiyun return -1;
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun frba = (struct frba_t *)(image + (((fdb->flmap0 >> 16) & 0xff) << 4));
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun for (i = 0; i < MAX_REGIONS; i++) {
452*4882a593Smuzhiyun struct region_t region;
453*4882a593Smuzhiyun int region_fd;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun ret = get_region(frba, i, ®ion);
456*4882a593Smuzhiyun if (ret)
457*4882a593Smuzhiyun return ret;
458*4882a593Smuzhiyun dump_region(i, frba);
459*4882a593Smuzhiyun if (region.size <= 0)
460*4882a593Smuzhiyun continue;
461*4882a593Smuzhiyun region_fd = open(region_filename(i),
462*4882a593Smuzhiyun O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR |
463*4882a593Smuzhiyun S_IWUSR | S_IRGRP | S_IROTH);
464*4882a593Smuzhiyun if (write(region_fd, image + region.base, region.size) !=
465*4882a593Smuzhiyun region.size) {
466*4882a593Smuzhiyun perror("Error while writing");
467*4882a593Smuzhiyun ret = -1;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun close(region_fd);
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun return ret;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun
perror_fname(const char * fmt,const char * fname)475*4882a593Smuzhiyun static int perror_fname(const char *fmt, const char *fname)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun char msg[strlen(fmt) + strlen(fname) + 1];
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun sprintf(msg, fmt, fname);
480*4882a593Smuzhiyun perror(msg);
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun return -1;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun /**
486*4882a593Smuzhiyun * write_image() - Write the image to a file
487*4882a593Smuzhiyun *
488*4882a593Smuzhiyun * @filename: Filename to use for the image
489*4882a593Smuzhiyun * @image: Pointer to image
490*4882a593Smuzhiyun * @size: Size of image in bytes
491*4882a593Smuzhiyun * @return 0 if OK, -ve on error
492*4882a593Smuzhiyun */
write_image(char * filename,char * image,int size)493*4882a593Smuzhiyun static int write_image(char *filename, char *image, int size)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun int new_fd;
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun debug("Writing new image to %s\n", filename);
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun new_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR |
500*4882a593Smuzhiyun S_IWUSR | S_IRGRP | S_IROTH);
501*4882a593Smuzhiyun if (new_fd < 0)
502*4882a593Smuzhiyun return perror_fname("Could not open file '%s'", filename);
503*4882a593Smuzhiyun if (write(new_fd, image, size) != size)
504*4882a593Smuzhiyun return perror_fname("Could not write file '%s'", filename);
505*4882a593Smuzhiyun close(new_fd);
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun return 0;
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun /**
511*4882a593Smuzhiyun * set_spi_frequency() - Set the SPI frequency to use when booting
512*4882a593Smuzhiyun *
513*4882a593Smuzhiyun * Several frequencies are supported, some of which work with fast devices.
514*4882a593Smuzhiyun * For SPI emulators, the slowest (SPI_FREQUENCY_20MHZ) is often used. The
515*4882a593Smuzhiyun * Intel boot system uses this information somehow on boot.
516*4882a593Smuzhiyun *
517*4882a593Smuzhiyun * The image is updated with the supplied value
518*4882a593Smuzhiyun *
519*4882a593Smuzhiyun * @image: Pointer to image
520*4882a593Smuzhiyun * @size: Size of image in bytes
521*4882a593Smuzhiyun * @freq: SPI frequency to use
522*4882a593Smuzhiyun */
set_spi_frequency(char * image,int size,enum spi_frequency freq)523*4882a593Smuzhiyun static void set_spi_frequency(char *image, int size, enum spi_frequency freq)
524*4882a593Smuzhiyun {
525*4882a593Smuzhiyun struct fdbar_t *fdb = find_fd(image, size);
526*4882a593Smuzhiyun struct fcba_t *fcba;
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun fcba = (struct fcba_t *)(image + (((fdb->flmap0) & 0xff) << 4));
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /* clear bits 21-29 */
531*4882a593Smuzhiyun fcba->flcomp &= ~0x3fe00000;
532*4882a593Smuzhiyun /* Read ID and Read Status Clock Frequency */
533*4882a593Smuzhiyun fcba->flcomp |= freq << 27;
534*4882a593Smuzhiyun /* Write and Erase Clock Frequency */
535*4882a593Smuzhiyun fcba->flcomp |= freq << 24;
536*4882a593Smuzhiyun /* Fast Read Clock Frequency */
537*4882a593Smuzhiyun fcba->flcomp |= freq << 21;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun /**
541*4882a593Smuzhiyun * set_em100_mode() - Set a SPI frequency that will work with Dediprog EM100
542*4882a593Smuzhiyun *
543*4882a593Smuzhiyun * @image: Pointer to image
544*4882a593Smuzhiyun * @size: Size of image in bytes
545*4882a593Smuzhiyun */
set_em100_mode(char * image,int size)546*4882a593Smuzhiyun static void set_em100_mode(char *image, int size)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun struct fdbar_t *fdb = find_fd(image, size);
549*4882a593Smuzhiyun struct fcba_t *fcba;
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun fcba = (struct fcba_t *)(image + (((fdb->flmap0) & 0xff) << 4));
552*4882a593Smuzhiyun fcba->flcomp &= ~(1 << 30);
553*4882a593Smuzhiyun set_spi_frequency(image, size, SPI_FREQUENCY_20MHZ);
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun /**
557*4882a593Smuzhiyun * lock_descriptor() - Lock the NE descriptor so it cannot be updated
558*4882a593Smuzhiyun *
559*4882a593Smuzhiyun * @image: Pointer to image
560*4882a593Smuzhiyun * @size: Size of image in bytes
561*4882a593Smuzhiyun */
lock_descriptor(char * image,int size)562*4882a593Smuzhiyun static void lock_descriptor(char *image, int size)
563*4882a593Smuzhiyun {
564*4882a593Smuzhiyun struct fdbar_t *fdb = find_fd(image, size);
565*4882a593Smuzhiyun struct fmba_t *fmba;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun /*
568*4882a593Smuzhiyun * TODO: Dynamically take Platform Data Region and GbE Region into
569*4882a593Smuzhiyun * account.
570*4882a593Smuzhiyun */
571*4882a593Smuzhiyun fmba = (struct fmba_t *)(image + (((fdb->flmap1) & 0xff) << 4));
572*4882a593Smuzhiyun fmba->flmstr1 = 0x0a0b0000;
573*4882a593Smuzhiyun fmba->flmstr2 = 0x0c0d0000;
574*4882a593Smuzhiyun fmba->flmstr3 = 0x08080118;
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun /**
578*4882a593Smuzhiyun * unlock_descriptor() - Lock the NE descriptor so it can be updated
579*4882a593Smuzhiyun *
580*4882a593Smuzhiyun * @image: Pointer to image
581*4882a593Smuzhiyun * @size: Size of image in bytes
582*4882a593Smuzhiyun */
unlock_descriptor(char * image,int size)583*4882a593Smuzhiyun static void unlock_descriptor(char *image, int size)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun struct fdbar_t *fdb = find_fd(image, size);
586*4882a593Smuzhiyun struct fmba_t *fmba;
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun fmba = (struct fmba_t *)(image + (((fdb->flmap1) & 0xff) << 4));
589*4882a593Smuzhiyun fmba->flmstr1 = 0xffff0000;
590*4882a593Smuzhiyun fmba->flmstr2 = 0xffff0000;
591*4882a593Smuzhiyun fmba->flmstr3 = 0x08080118;
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun /**
595*4882a593Smuzhiyun * open_for_read() - Open a file for reading
596*4882a593Smuzhiyun *
597*4882a593Smuzhiyun * @fname: Filename to open
598*4882a593Smuzhiyun * @sizep: Returns file size in bytes
599*4882a593Smuzhiyun * @return 0 if OK, -1 on error
600*4882a593Smuzhiyun */
open_for_read(const char * fname,int * sizep)601*4882a593Smuzhiyun int open_for_read(const char *fname, int *sizep)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun int fd = open(fname, O_RDONLY);
604*4882a593Smuzhiyun struct stat buf;
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun if (fd == -1)
607*4882a593Smuzhiyun return perror_fname("Could not open file '%s'", fname);
608*4882a593Smuzhiyun if (fstat(fd, &buf) == -1)
609*4882a593Smuzhiyun return perror_fname("Could not stat file '%s'", fname);
610*4882a593Smuzhiyun *sizep = buf.st_size;
611*4882a593Smuzhiyun debug("File %s is %d bytes\n", fname, *sizep);
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun return fd;
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun /**
617*4882a593Smuzhiyun * inject_region() - Add a file to an image region
618*4882a593Smuzhiyun *
619*4882a593Smuzhiyun * This puts a file into a particular region of the flash. Several pre-defined
620*4882a593Smuzhiyun * regions are used.
621*4882a593Smuzhiyun *
622*4882a593Smuzhiyun * @image: Pointer to image
623*4882a593Smuzhiyun * @size: Size of image in bytes
624*4882a593Smuzhiyun * @region_type: Region where the file should be added
625*4882a593Smuzhiyun * @region_fname: Filename to add to the image
626*4882a593Smuzhiyun * @return 0 if OK, -ve on error
627*4882a593Smuzhiyun */
inject_region(char * image,int size,int region_type,char * region_fname)628*4882a593Smuzhiyun int inject_region(char *image, int size, int region_type, char *region_fname)
629*4882a593Smuzhiyun {
630*4882a593Smuzhiyun struct fdbar_t *fdb = find_fd(image, size);
631*4882a593Smuzhiyun struct region_t region;
632*4882a593Smuzhiyun struct frba_t *frba;
633*4882a593Smuzhiyun int region_size;
634*4882a593Smuzhiyun int offset = 0;
635*4882a593Smuzhiyun int region_fd;
636*4882a593Smuzhiyun int ret;
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun if (!fdb)
639*4882a593Smuzhiyun exit(EXIT_FAILURE);
640*4882a593Smuzhiyun frba = (struct frba_t *)(image + (((fdb->flmap0 >> 16) & 0xff) << 4));
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun ret = get_region(frba, region_type, ®ion);
643*4882a593Smuzhiyun if (ret)
644*4882a593Smuzhiyun return -1;
645*4882a593Smuzhiyun if (region.size <= 0xfff) {
646*4882a593Smuzhiyun fprintf(stderr, "Region %s is disabled in target. Not injecting.\n",
647*4882a593Smuzhiyun region_name(region_type));
648*4882a593Smuzhiyun return -1;
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun region_fd = open_for_read(region_fname, ®ion_size);
652*4882a593Smuzhiyun if (region_fd < 0)
653*4882a593Smuzhiyun return region_fd;
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun if ((region_size > region.size) ||
656*4882a593Smuzhiyun ((region_type != 1) && (region_size > region.size))) {
657*4882a593Smuzhiyun fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x) bytes. Not injecting.\n",
658*4882a593Smuzhiyun region_name(region_type), region.size,
659*4882a593Smuzhiyun region.size, region_size, region_size);
660*4882a593Smuzhiyun return -1;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun if ((region_type == 1) && (region_size < region.size)) {
664*4882a593Smuzhiyun fprintf(stderr, "Region %s is %d(0x%x) bytes. File is %d(0x%x) bytes. Padding before injecting.\n",
665*4882a593Smuzhiyun region_name(region_type), region.size,
666*4882a593Smuzhiyun region.size, region_size, region_size);
667*4882a593Smuzhiyun offset = region.size - region_size;
668*4882a593Smuzhiyun memset(image + region.base, 0xff, offset);
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun if (size < region.base + offset + region_size) {
672*4882a593Smuzhiyun fprintf(stderr, "Output file is too small. (%d < %d)\n",
673*4882a593Smuzhiyun size, region.base + offset + region_size);
674*4882a593Smuzhiyun return -1;
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun if (read(region_fd, image + region.base + offset, region_size)
678*4882a593Smuzhiyun != region_size) {
679*4882a593Smuzhiyun perror("Could not read file");
680*4882a593Smuzhiyun return -1;
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun close(region_fd);
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun debug("Adding %s as the %s section\n", region_fname,
686*4882a593Smuzhiyun region_name(region_type));
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun return 0;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun /**
692*4882a593Smuzhiyun * write_data() - Write some raw data into a region
693*4882a593Smuzhiyun *
694*4882a593Smuzhiyun * This puts a file into a particular place in the flash, ignoring the
695*4882a593Smuzhiyun * regions. Be careful not to overwrite something important.
696*4882a593Smuzhiyun *
697*4882a593Smuzhiyun * @image: Pointer to image
698*4882a593Smuzhiyun * @size: Size of image in bytes
699*4882a593Smuzhiyun * @addr: x86 ROM address to put file. The ROM ends at
700*4882a593Smuzhiyun * 0xffffffff so use an address relative to that. For an
701*4882a593Smuzhiyun * 8MB ROM the start address is 0xfff80000.
702*4882a593Smuzhiyun * @write_fname: Filename to add to the image
703*4882a593Smuzhiyun * @offset_uboot_top: Offset of the top of U-Boot
704*4882a593Smuzhiyun * @offset_uboot_start: Offset of the start of U-Boot
705*4882a593Smuzhiyun * @return number of bytes written if OK, -ve on error
706*4882a593Smuzhiyun */
write_data(char * image,int size,unsigned int addr,const char * write_fname,int offset_uboot_top,int offset_uboot_start)707*4882a593Smuzhiyun static int write_data(char *image, int size, unsigned int addr,
708*4882a593Smuzhiyun const char *write_fname, int offset_uboot_top,
709*4882a593Smuzhiyun int offset_uboot_start)
710*4882a593Smuzhiyun {
711*4882a593Smuzhiyun int write_fd, write_size;
712*4882a593Smuzhiyun int offset;
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun write_fd = open_for_read(write_fname, &write_size);
715*4882a593Smuzhiyun if (write_fd < 0)
716*4882a593Smuzhiyun return write_fd;
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun offset = (uint32_t)(addr + size);
719*4882a593Smuzhiyun if (offset_uboot_top) {
720*4882a593Smuzhiyun if (offset_uboot_start < offset &&
721*4882a593Smuzhiyun offset_uboot_top >= offset) {
722*4882a593Smuzhiyun fprintf(stderr, "U-Boot image overlaps with region '%s'\n",
723*4882a593Smuzhiyun write_fname);
724*4882a593Smuzhiyun fprintf(stderr,
725*4882a593Smuzhiyun "U-Boot finishes at offset %x, file starts at %x\n",
726*4882a593Smuzhiyun offset_uboot_top, offset);
727*4882a593Smuzhiyun return -EXDEV;
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun if (offset_uboot_start > offset &&
730*4882a593Smuzhiyun offset_uboot_start <= offset + write_size) {
731*4882a593Smuzhiyun fprintf(stderr, "U-Boot image overlaps with region '%s'\n",
732*4882a593Smuzhiyun write_fname);
733*4882a593Smuzhiyun fprintf(stderr,
734*4882a593Smuzhiyun "U-Boot starts at offset %x, file finishes at %x\n",
735*4882a593Smuzhiyun offset_uboot_start, offset + write_size);
736*4882a593Smuzhiyun return -EXDEV;
737*4882a593Smuzhiyun }
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun debug("Writing %s to offset %#x\n", write_fname, offset);
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun if (offset < 0 || offset + write_size > size) {
742*4882a593Smuzhiyun fprintf(stderr, "Output file is too small. (%d < %d)\n",
743*4882a593Smuzhiyun size, offset + write_size);
744*4882a593Smuzhiyun return -1;
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun if (read(write_fd, image + offset, write_size) != write_size) {
748*4882a593Smuzhiyun perror("Could not read file");
749*4882a593Smuzhiyun return -1;
750*4882a593Smuzhiyun }
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun close(write_fd);
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun return write_size;
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun
print_version(void)757*4882a593Smuzhiyun static void print_version(void)
758*4882a593Smuzhiyun {
759*4882a593Smuzhiyun printf("ifdtool v%s -- ", IFDTOOL_VERSION);
760*4882a593Smuzhiyun printf("Copyright (C) 2014 Google Inc.\n\n");
761*4882a593Smuzhiyun printf("SPDX-License-Identifier: GPL-2.0+\n");
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun
print_usage(const char * name)764*4882a593Smuzhiyun static void print_usage(const char *name)
765*4882a593Smuzhiyun {
766*4882a593Smuzhiyun printf("usage: %s [-vhdix?] <filename> [<outfile>]\n", name);
767*4882a593Smuzhiyun printf("\n"
768*4882a593Smuzhiyun " -d | --dump: dump intel firmware descriptor\n"
769*4882a593Smuzhiyun " -x | --extract: extract intel fd modules\n"
770*4882a593Smuzhiyun " -i | --inject <region>:<module> inject file <module> into region <region>\n"
771*4882a593Smuzhiyun " -w | --write <addr>:<file> write file to appear at memory address <addr>\n"
772*4882a593Smuzhiyun " multiple files can be written simultaneously\n"
773*4882a593Smuzhiyun " -s | --spifreq <20|33|50> set the SPI frequency\n"
774*4882a593Smuzhiyun " -e | --em100 set SPI frequency to 20MHz and disable\n"
775*4882a593Smuzhiyun " Dual Output Fast Read Support\n"
776*4882a593Smuzhiyun " -l | --lock Lock firmware descriptor and ME region\n"
777*4882a593Smuzhiyun " -u | --unlock Unlock firmware descriptor and ME region\n"
778*4882a593Smuzhiyun " -r | --romsize Specify ROM size\n"
779*4882a593Smuzhiyun " -D | --write-descriptor <file> Write descriptor at base\n"
780*4882a593Smuzhiyun " -c | --create Create a new empty image\n"
781*4882a593Smuzhiyun " -v | --version: print the version\n"
782*4882a593Smuzhiyun " -h | --help: print this help\n\n"
783*4882a593Smuzhiyun "<region> is one of Descriptor, BIOS, ME, GbE, Platform\n"
784*4882a593Smuzhiyun "\n");
785*4882a593Smuzhiyun }
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun /**
788*4882a593Smuzhiyun * get_two_words() - Convert a string into two words separated by :
789*4882a593Smuzhiyun *
790*4882a593Smuzhiyun * The supplied string is split at ':', two substrings are allocated and
791*4882a593Smuzhiyun * returned.
792*4882a593Smuzhiyun *
793*4882a593Smuzhiyun * @str: String to split
794*4882a593Smuzhiyun * @firstp: Returns first string
795*4882a593Smuzhiyun * @secondp: Returns second string
796*4882a593Smuzhiyun * @return 0 if OK, -ve if @str does not have a :
797*4882a593Smuzhiyun */
get_two_words(const char * str,char ** firstp,char ** secondp)798*4882a593Smuzhiyun static int get_two_words(const char *str, char **firstp, char **secondp)
799*4882a593Smuzhiyun {
800*4882a593Smuzhiyun const char *p;
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun p = strchr(str, ':');
803*4882a593Smuzhiyun if (!p)
804*4882a593Smuzhiyun return -1;
805*4882a593Smuzhiyun *firstp = strdup(str);
806*4882a593Smuzhiyun (*firstp)[p - str] = '\0';
807*4882a593Smuzhiyun *secondp = strdup(p + 1);
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun return 0;
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun
main(int argc,char * argv[])812*4882a593Smuzhiyun int main(int argc, char *argv[])
813*4882a593Smuzhiyun {
814*4882a593Smuzhiyun int opt, option_index = 0;
815*4882a593Smuzhiyun int mode_dump = 0, mode_extract = 0, mode_inject = 0;
816*4882a593Smuzhiyun int mode_spifreq = 0, mode_em100 = 0, mode_locked = 0;
817*4882a593Smuzhiyun int mode_unlocked = 0, mode_write = 0, mode_write_descriptor = 0;
818*4882a593Smuzhiyun int create = 0;
819*4882a593Smuzhiyun char *region_type_string = NULL, *inject_fname = NULL;
820*4882a593Smuzhiyun char *desc_fname = NULL, *addr_str = NULL;
821*4882a593Smuzhiyun int region_type = -1, inputfreq = 0;
822*4882a593Smuzhiyun enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
823*4882a593Smuzhiyun struct input_file input_file[WRITE_MAX], *ifile, *fdt = NULL;
824*4882a593Smuzhiyun unsigned char wr_idx, wr_num = 0;
825*4882a593Smuzhiyun int rom_size = -1;
826*4882a593Smuzhiyun bool write_it;
827*4882a593Smuzhiyun char *filename;
828*4882a593Smuzhiyun char *outfile = NULL;
829*4882a593Smuzhiyun struct stat buf;
830*4882a593Smuzhiyun int size = 0;
831*4882a593Smuzhiyun bool have_uboot = false;
832*4882a593Smuzhiyun int bios_fd;
833*4882a593Smuzhiyun char *image;
834*4882a593Smuzhiyun int ret;
835*4882a593Smuzhiyun static struct option long_options[] = {
836*4882a593Smuzhiyun {"create", 0, NULL, 'c'},
837*4882a593Smuzhiyun {"dump", 0, NULL, 'd'},
838*4882a593Smuzhiyun {"descriptor", 1, NULL, 'D'},
839*4882a593Smuzhiyun {"em100", 0, NULL, 'e'},
840*4882a593Smuzhiyun {"extract", 0, NULL, 'x'},
841*4882a593Smuzhiyun {"fdt", 1, NULL, 'f'},
842*4882a593Smuzhiyun {"inject", 1, NULL, 'i'},
843*4882a593Smuzhiyun {"lock", 0, NULL, 'l'},
844*4882a593Smuzhiyun {"romsize", 1, NULL, 'r'},
845*4882a593Smuzhiyun {"spifreq", 1, NULL, 's'},
846*4882a593Smuzhiyun {"unlock", 0, NULL, 'u'},
847*4882a593Smuzhiyun {"uboot", 1, NULL, 'U'},
848*4882a593Smuzhiyun {"write", 1, NULL, 'w'},
849*4882a593Smuzhiyun {"version", 0, NULL, 'v'},
850*4882a593Smuzhiyun {"help", 0, NULL, 'h'},
851*4882a593Smuzhiyun {0, 0, 0, 0}
852*4882a593Smuzhiyun };
853*4882a593Smuzhiyun
854*4882a593Smuzhiyun while ((opt = getopt_long(argc, argv, "cdD:ef:hi:lr:s:uU:vw:x?",
855*4882a593Smuzhiyun long_options, &option_index)) != EOF) {
856*4882a593Smuzhiyun switch (opt) {
857*4882a593Smuzhiyun case 'c':
858*4882a593Smuzhiyun create = 1;
859*4882a593Smuzhiyun break;
860*4882a593Smuzhiyun case 'd':
861*4882a593Smuzhiyun mode_dump = 1;
862*4882a593Smuzhiyun break;
863*4882a593Smuzhiyun case 'D':
864*4882a593Smuzhiyun mode_write_descriptor = 1;
865*4882a593Smuzhiyun desc_fname = optarg;
866*4882a593Smuzhiyun break;
867*4882a593Smuzhiyun case 'e':
868*4882a593Smuzhiyun mode_em100 = 1;
869*4882a593Smuzhiyun break;
870*4882a593Smuzhiyun case 'i':
871*4882a593Smuzhiyun if (get_two_words(optarg, ®ion_type_string,
872*4882a593Smuzhiyun &inject_fname)) {
873*4882a593Smuzhiyun print_usage(argv[0]);
874*4882a593Smuzhiyun exit(EXIT_FAILURE);
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun if (!strcasecmp("Descriptor", region_type_string))
877*4882a593Smuzhiyun region_type = 0;
878*4882a593Smuzhiyun else if (!strcasecmp("BIOS", region_type_string))
879*4882a593Smuzhiyun region_type = 1;
880*4882a593Smuzhiyun else if (!strcasecmp("ME", region_type_string))
881*4882a593Smuzhiyun region_type = 2;
882*4882a593Smuzhiyun else if (!strcasecmp("GbE", region_type_string))
883*4882a593Smuzhiyun region_type = 3;
884*4882a593Smuzhiyun else if (!strcasecmp("Platform", region_type_string))
885*4882a593Smuzhiyun region_type = 4;
886*4882a593Smuzhiyun if (region_type == -1) {
887*4882a593Smuzhiyun fprintf(stderr, "No such region type: '%s'\n\n",
888*4882a593Smuzhiyun region_type_string);
889*4882a593Smuzhiyun print_usage(argv[0]);
890*4882a593Smuzhiyun exit(EXIT_FAILURE);
891*4882a593Smuzhiyun }
892*4882a593Smuzhiyun mode_inject = 1;
893*4882a593Smuzhiyun break;
894*4882a593Smuzhiyun case 'l':
895*4882a593Smuzhiyun mode_locked = 1;
896*4882a593Smuzhiyun break;
897*4882a593Smuzhiyun case 'r':
898*4882a593Smuzhiyun rom_size = strtol(optarg, NULL, 0);
899*4882a593Smuzhiyun debug("ROM size %d\n", rom_size);
900*4882a593Smuzhiyun break;
901*4882a593Smuzhiyun case 's':
902*4882a593Smuzhiyun /* Parse the requested SPI frequency */
903*4882a593Smuzhiyun inputfreq = strtol(optarg, NULL, 0);
904*4882a593Smuzhiyun switch (inputfreq) {
905*4882a593Smuzhiyun case 20:
906*4882a593Smuzhiyun spifreq = SPI_FREQUENCY_20MHZ;
907*4882a593Smuzhiyun break;
908*4882a593Smuzhiyun case 33:
909*4882a593Smuzhiyun spifreq = SPI_FREQUENCY_33MHZ;
910*4882a593Smuzhiyun break;
911*4882a593Smuzhiyun case 50:
912*4882a593Smuzhiyun spifreq = SPI_FREQUENCY_50MHZ;
913*4882a593Smuzhiyun break;
914*4882a593Smuzhiyun default:
915*4882a593Smuzhiyun fprintf(stderr, "Invalid SPI Frequency: %d\n",
916*4882a593Smuzhiyun inputfreq);
917*4882a593Smuzhiyun print_usage(argv[0]);
918*4882a593Smuzhiyun exit(EXIT_FAILURE);
919*4882a593Smuzhiyun }
920*4882a593Smuzhiyun mode_spifreq = 1;
921*4882a593Smuzhiyun break;
922*4882a593Smuzhiyun case 'u':
923*4882a593Smuzhiyun mode_unlocked = 1;
924*4882a593Smuzhiyun break;
925*4882a593Smuzhiyun case 'v':
926*4882a593Smuzhiyun print_version();
927*4882a593Smuzhiyun exit(EXIT_SUCCESS);
928*4882a593Smuzhiyun break;
929*4882a593Smuzhiyun case 'w':
930*4882a593Smuzhiyun case 'U':
931*4882a593Smuzhiyun case 'f':
932*4882a593Smuzhiyun ifile = &input_file[wr_num];
933*4882a593Smuzhiyun mode_write = 1;
934*4882a593Smuzhiyun if (wr_num < WRITE_MAX) {
935*4882a593Smuzhiyun if (get_two_words(optarg, &addr_str,
936*4882a593Smuzhiyun &ifile->fname)) {
937*4882a593Smuzhiyun print_usage(argv[0]);
938*4882a593Smuzhiyun exit(EXIT_FAILURE);
939*4882a593Smuzhiyun }
940*4882a593Smuzhiyun ifile->addr = strtoll(optarg, NULL, 0);
941*4882a593Smuzhiyun wr_num++;
942*4882a593Smuzhiyun } else {
943*4882a593Smuzhiyun fprintf(stderr,
944*4882a593Smuzhiyun "The number of files to write simultaneously exceeds the limitation (%d)\n",
945*4882a593Smuzhiyun WRITE_MAX);
946*4882a593Smuzhiyun }
947*4882a593Smuzhiyun break;
948*4882a593Smuzhiyun case 'x':
949*4882a593Smuzhiyun mode_extract = 1;
950*4882a593Smuzhiyun break;
951*4882a593Smuzhiyun case 'h':
952*4882a593Smuzhiyun case '?':
953*4882a593Smuzhiyun default:
954*4882a593Smuzhiyun print_usage(argv[0]);
955*4882a593Smuzhiyun exit(EXIT_SUCCESS);
956*4882a593Smuzhiyun break;
957*4882a593Smuzhiyun }
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun if (mode_locked == 1 && mode_unlocked == 1) {
961*4882a593Smuzhiyun fprintf(stderr, "Locking/Unlocking FD and ME are mutually exclusive\n");
962*4882a593Smuzhiyun exit(EXIT_FAILURE);
963*4882a593Smuzhiyun }
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun if (mode_inject == 1 && mode_write == 1) {
966*4882a593Smuzhiyun fprintf(stderr, "Inject/Write are mutually exclusive\n");
967*4882a593Smuzhiyun exit(EXIT_FAILURE);
968*4882a593Smuzhiyun }
969*4882a593Smuzhiyun
970*4882a593Smuzhiyun if ((mode_dump + mode_extract + mode_inject +
971*4882a593Smuzhiyun (mode_spifreq | mode_em100 | mode_unlocked |
972*4882a593Smuzhiyun mode_locked)) > 1) {
973*4882a593Smuzhiyun fprintf(stderr, "You may not specify more than one mode.\n\n");
974*4882a593Smuzhiyun print_usage(argv[0]);
975*4882a593Smuzhiyun exit(EXIT_FAILURE);
976*4882a593Smuzhiyun }
977*4882a593Smuzhiyun
978*4882a593Smuzhiyun if ((mode_dump + mode_extract + mode_inject + mode_spifreq +
979*4882a593Smuzhiyun mode_em100 + mode_locked + mode_unlocked + mode_write +
980*4882a593Smuzhiyun mode_write_descriptor) == 0 && !create) {
981*4882a593Smuzhiyun fprintf(stderr, "You need to specify a mode.\n\n");
982*4882a593Smuzhiyun print_usage(argv[0]);
983*4882a593Smuzhiyun exit(EXIT_FAILURE);
984*4882a593Smuzhiyun }
985*4882a593Smuzhiyun
986*4882a593Smuzhiyun if (create && rom_size == -1) {
987*4882a593Smuzhiyun fprintf(stderr, "You need to specify a rom size when creating.\n\n");
988*4882a593Smuzhiyun exit(EXIT_FAILURE);
989*4882a593Smuzhiyun }
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun if (optind + 1 != argc) {
992*4882a593Smuzhiyun fprintf(stderr, "You need to specify a file.\n\n");
993*4882a593Smuzhiyun print_usage(argv[0]);
994*4882a593Smuzhiyun exit(EXIT_FAILURE);
995*4882a593Smuzhiyun }
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun if (have_uboot && !fdt) {
998*4882a593Smuzhiyun fprintf(stderr,
999*4882a593Smuzhiyun "You must supply a device tree file for U-Boot\n\n");
1000*4882a593Smuzhiyun print_usage(argv[0]);
1001*4882a593Smuzhiyun exit(EXIT_FAILURE);
1002*4882a593Smuzhiyun }
1003*4882a593Smuzhiyun
1004*4882a593Smuzhiyun filename = argv[optind];
1005*4882a593Smuzhiyun if (optind + 2 != argc)
1006*4882a593Smuzhiyun outfile = argv[optind + 1];
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun if (create)
1009*4882a593Smuzhiyun bios_fd = open(filename, O_WRONLY | O_CREAT, 0666);
1010*4882a593Smuzhiyun else
1011*4882a593Smuzhiyun bios_fd = open(filename, outfile ? O_RDONLY : O_RDWR);
1012*4882a593Smuzhiyun
1013*4882a593Smuzhiyun if (bios_fd == -1) {
1014*4882a593Smuzhiyun perror("Could not open file");
1015*4882a593Smuzhiyun exit(EXIT_FAILURE);
1016*4882a593Smuzhiyun }
1017*4882a593Smuzhiyun
1018*4882a593Smuzhiyun if (!create) {
1019*4882a593Smuzhiyun if (fstat(bios_fd, &buf) == -1) {
1020*4882a593Smuzhiyun perror("Could not stat file");
1021*4882a593Smuzhiyun exit(EXIT_FAILURE);
1022*4882a593Smuzhiyun }
1023*4882a593Smuzhiyun size = buf.st_size;
1024*4882a593Smuzhiyun }
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun debug("File %s is %d bytes\n", filename, size);
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun if (rom_size == -1)
1029*4882a593Smuzhiyun rom_size = size;
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun image = malloc(rom_size);
1032*4882a593Smuzhiyun if (!image) {
1033*4882a593Smuzhiyun printf("Out of memory.\n");
1034*4882a593Smuzhiyun exit(EXIT_FAILURE);
1035*4882a593Smuzhiyun }
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun memset(image, '\xff', rom_size);
1038*4882a593Smuzhiyun if (!create && read(bios_fd, image, size) != size) {
1039*4882a593Smuzhiyun perror("Could not read file");
1040*4882a593Smuzhiyun exit(EXIT_FAILURE);
1041*4882a593Smuzhiyun }
1042*4882a593Smuzhiyun if (size != rom_size) {
1043*4882a593Smuzhiyun debug("ROM size changed to %d bytes\n", rom_size);
1044*4882a593Smuzhiyun size = rom_size;
1045*4882a593Smuzhiyun }
1046*4882a593Smuzhiyun
1047*4882a593Smuzhiyun write_it = true;
1048*4882a593Smuzhiyun ret = 0;
1049*4882a593Smuzhiyun if (mode_dump) {
1050*4882a593Smuzhiyun ret = dump_fd(image, size);
1051*4882a593Smuzhiyun write_it = false;
1052*4882a593Smuzhiyun }
1053*4882a593Smuzhiyun
1054*4882a593Smuzhiyun if (mode_extract) {
1055*4882a593Smuzhiyun ret = write_regions(image, size);
1056*4882a593Smuzhiyun write_it = false;
1057*4882a593Smuzhiyun }
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun if (mode_write_descriptor)
1060*4882a593Smuzhiyun ret = write_data(image, size, -size, desc_fname, 0, 0);
1061*4882a593Smuzhiyun
1062*4882a593Smuzhiyun if (mode_inject)
1063*4882a593Smuzhiyun ret = inject_region(image, size, region_type, inject_fname);
1064*4882a593Smuzhiyun
1065*4882a593Smuzhiyun if (mode_write) {
1066*4882a593Smuzhiyun int offset_uboot_top = 0;
1067*4882a593Smuzhiyun int offset_uboot_start = 0;
1068*4882a593Smuzhiyun
1069*4882a593Smuzhiyun for (wr_idx = 0; wr_idx < wr_num; wr_idx++) {
1070*4882a593Smuzhiyun ifile = &input_file[wr_idx];
1071*4882a593Smuzhiyun ret = write_data(image, size, ifile->addr,
1072*4882a593Smuzhiyun ifile->fname, offset_uboot_top,
1073*4882a593Smuzhiyun offset_uboot_start);
1074*4882a593Smuzhiyun if (ret < 0)
1075*4882a593Smuzhiyun break;
1076*4882a593Smuzhiyun }
1077*4882a593Smuzhiyun }
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun if (mode_spifreq)
1080*4882a593Smuzhiyun set_spi_frequency(image, size, spifreq);
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun if (mode_em100)
1083*4882a593Smuzhiyun set_em100_mode(image, size);
1084*4882a593Smuzhiyun
1085*4882a593Smuzhiyun if (mode_locked)
1086*4882a593Smuzhiyun lock_descriptor(image, size);
1087*4882a593Smuzhiyun
1088*4882a593Smuzhiyun if (mode_unlocked)
1089*4882a593Smuzhiyun unlock_descriptor(image, size);
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun if (write_it) {
1092*4882a593Smuzhiyun if (outfile) {
1093*4882a593Smuzhiyun ret = write_image(outfile, image, size);
1094*4882a593Smuzhiyun } else {
1095*4882a593Smuzhiyun if (lseek(bios_fd, 0, SEEK_SET)) {
1096*4882a593Smuzhiyun perror("Error while seeking");
1097*4882a593Smuzhiyun ret = -1;
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun if (write(bios_fd, image, size) != size) {
1100*4882a593Smuzhiyun perror("Error while writing");
1101*4882a593Smuzhiyun ret = -1;
1102*4882a593Smuzhiyun }
1103*4882a593Smuzhiyun }
1104*4882a593Smuzhiyun }
1105*4882a593Smuzhiyun
1106*4882a593Smuzhiyun free(image);
1107*4882a593Smuzhiyun close(bios_fd);
1108*4882a593Smuzhiyun
1109*4882a593Smuzhiyun return ret < 0 ? 1 : 0;
1110*4882a593Smuzhiyun }
1111