xref: /OK3568_Linux_fs/u-boot/tools/ifdtool.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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, &region);
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, &region);
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, &region);
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, &region_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, &region_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