xref: /aosp_15_r20/external/arm-trusted-firmware/tools/sptool/sptool.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park  * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
3*54fd6939SJiyong Park  *
4*54fd6939SJiyong Park  * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park  */
6*54fd6939SJiyong Park 
7*54fd6939SJiyong Park #include <stdarg.h>
8*54fd6939SJiyong Park #include <stdbool.h>
9*54fd6939SJiyong Park #include <stdint.h>
10*54fd6939SJiyong Park #include <stdio.h>
11*54fd6939SJiyong Park #include <stdlib.h>
12*54fd6939SJiyong Park #include <string.h>
13*54fd6939SJiyong Park #include <unistd.h>
14*54fd6939SJiyong Park 
15*54fd6939SJiyong Park #include "sptool.h"
16*54fd6939SJiyong Park 
17*54fd6939SJiyong Park #define PAGE_SIZE		4096
18*54fd6939SJiyong Park 
19*54fd6939SJiyong Park /*
20*54fd6939SJiyong Park  * Entry describing Secure Partition package.
21*54fd6939SJiyong Park  */
22*54fd6939SJiyong Park struct sp_pkg_info {
23*54fd6939SJiyong Park 	/* Location of the files in the host's RAM. */
24*54fd6939SJiyong Park 	void *img_data, *pm_data;
25*54fd6939SJiyong Park 
26*54fd6939SJiyong Park 	/* Size of the files. */
27*54fd6939SJiyong Park 	uint32_t img_size, pm_size;
28*54fd6939SJiyong Park 
29*54fd6939SJiyong Park 	/* Location of the binary files inside the package output file */
30*54fd6939SJiyong Park 	uint32_t img_offset, pm_offset;
31*54fd6939SJiyong Park };
32*54fd6939SJiyong Park 
33*54fd6939SJiyong Park /*
34*54fd6939SJiyong Park  * List of input provided by user
35*54fd6939SJiyong Park  */
36*54fd6939SJiyong Park struct arg_list {
37*54fd6939SJiyong Park 	char *usr_input;
38*54fd6939SJiyong Park 	struct arg_list *next;
39*54fd6939SJiyong Park };
40*54fd6939SJiyong Park 
41*54fd6939SJiyong Park /* Align an address to a power-of-two boundary. */
align_to(unsigned int address,unsigned int boundary)42*54fd6939SJiyong Park static unsigned int align_to(unsigned int address, unsigned int boundary)
43*54fd6939SJiyong Park {
44*54fd6939SJiyong Park 	unsigned int mask = boundary - 1U;
45*54fd6939SJiyong Park 
46*54fd6939SJiyong Park 	if ((address & mask) != 0U)
47*54fd6939SJiyong Park 		return (address + boundary) & ~mask;
48*54fd6939SJiyong Park 	else
49*54fd6939SJiyong Park 		return address;
50*54fd6939SJiyong Park }
51*54fd6939SJiyong Park 
52*54fd6939SJiyong Park /* Allocate a memory area of 'size' bytes and zero it. */
xzalloc(size_t size,const char * msg)53*54fd6939SJiyong Park static void *xzalloc(size_t size, const char *msg)
54*54fd6939SJiyong Park {
55*54fd6939SJiyong Park 	void *d;
56*54fd6939SJiyong Park 
57*54fd6939SJiyong Park 	d = malloc(size);
58*54fd6939SJiyong Park 	if (d == NULL) {
59*54fd6939SJiyong Park 		fprintf(stderr, "error: malloc: %s\n", msg);
60*54fd6939SJiyong Park 		exit(1);
61*54fd6939SJiyong Park 	}
62*54fd6939SJiyong Park 
63*54fd6939SJiyong Park 	memset(d, 0, size);
64*54fd6939SJiyong Park 
65*54fd6939SJiyong Park 	return d;
66*54fd6939SJiyong Park }
67*54fd6939SJiyong Park 
68*54fd6939SJiyong Park /*
69*54fd6939SJiyong Park  * Write 'size' bytes from 'buf' into the specified file stream.
70*54fd6939SJiyong Park  * Exit the program on error.
71*54fd6939SJiyong Park  */
xfwrite(void * buf,size_t size,FILE * fp)72*54fd6939SJiyong Park static void xfwrite(void *buf, size_t size, FILE *fp)
73*54fd6939SJiyong Park {
74*54fd6939SJiyong Park 	if (fwrite(buf, 1, size, fp) != size) {
75*54fd6939SJiyong Park 		fprintf(stderr, "error: Failed to write to output file.\n");
76*54fd6939SJiyong Park 		exit(1);
77*54fd6939SJiyong Park 	}
78*54fd6939SJiyong Park }
79*54fd6939SJiyong Park 
80*54fd6939SJiyong Park /*
81*54fd6939SJiyong Park  * Set the file position indicator for the specified file stream.
82*54fd6939SJiyong Park  * Exit the program on error.
83*54fd6939SJiyong Park  */
xfseek(FILE * fp,long offset,int whence)84*54fd6939SJiyong Park static void xfseek(FILE *fp, long offset, int whence)
85*54fd6939SJiyong Park {
86*54fd6939SJiyong Park 	if (fseek(fp, offset, whence) != 0) {
87*54fd6939SJiyong Park 		fprintf(stderr, "error: Failed to set file to offset 0x%lx (%d).\n",
88*54fd6939SJiyong Park 		       offset, whence);
89*54fd6939SJiyong Park 		perror(NULL);
90*54fd6939SJiyong Park 		exit(1);
91*54fd6939SJiyong Park 	}
92*54fd6939SJiyong Park }
93*54fd6939SJiyong Park 
94*54fd6939SJiyong Park /*
95*54fd6939SJiyong Park  * Free SP package structure
96*54fd6939SJiyong Park  */
cleanup(struct sp_pkg_info * sp)97*54fd6939SJiyong Park static void cleanup(struct sp_pkg_info *sp)
98*54fd6939SJiyong Park {
99*54fd6939SJiyong Park 
100*54fd6939SJiyong Park 	if (sp != NULL) {
101*54fd6939SJiyong Park 		if (sp->img_data != NULL) {
102*54fd6939SJiyong Park 			free(sp->img_data);
103*54fd6939SJiyong Park 		}
104*54fd6939SJiyong Park 
105*54fd6939SJiyong Park 		if (sp->pm_data != NULL) {
106*54fd6939SJiyong Park 			free(sp->pm_data);
107*54fd6939SJiyong Park 		}
108*54fd6939SJiyong Park 
109*54fd6939SJiyong Park 		free(sp);
110*54fd6939SJiyong Park 
111*54fd6939SJiyong Park 	}
112*54fd6939SJiyong Park }
113*54fd6939SJiyong Park 
114*54fd6939SJiyong Park /*
115*54fd6939SJiyong Park  * Free argument list structure
116*54fd6939SJiyong Park  */
freelist(struct arg_list * head)117*54fd6939SJiyong Park static void freelist(struct arg_list *head)
118*54fd6939SJiyong Park {
119*54fd6939SJiyong Park 	struct arg_list *tmp;
120*54fd6939SJiyong Park 
121*54fd6939SJiyong Park 	while (head != NULL) {
122*54fd6939SJiyong Park 		tmp = head;
123*54fd6939SJiyong Park 		head = head->next;
124*54fd6939SJiyong Park 		free(tmp);
125*54fd6939SJiyong Park 	}
126*54fd6939SJiyong Park }
127*54fd6939SJiyong Park 
128*54fd6939SJiyong Park /*
129*54fd6939SJiyong Park  * Append user inputs in argument list structure
130*54fd6939SJiyong Park  */
append_user_input(struct arg_list ** head,char * args)131*54fd6939SJiyong Park static void append_user_input(struct arg_list **head, char *args)
132*54fd6939SJiyong Park {
133*54fd6939SJiyong Park 	struct arg_list *tmp = *head;
134*54fd6939SJiyong Park 
135*54fd6939SJiyong Park 	if (tmp == NULL) {
136*54fd6939SJiyong Park 		tmp = xzalloc(sizeof(struct arg_list),
137*54fd6939SJiyong Park 				"Failed to allocate arg_list struct");
138*54fd6939SJiyong Park 		tmp->usr_input = args;
139*54fd6939SJiyong Park 		*head = tmp;
140*54fd6939SJiyong Park 	} else {
141*54fd6939SJiyong Park 		while (tmp->next != NULL) {
142*54fd6939SJiyong Park 			tmp = tmp->next;
143*54fd6939SJiyong Park 		}
144*54fd6939SJiyong Park 		tmp->next = xzalloc(sizeof(struct arg_list),
145*54fd6939SJiyong Park 				"Failed to allocate arg_list struct");
146*54fd6939SJiyong Park 		tmp = tmp->next;
147*54fd6939SJiyong Park 		tmp->usr_input = args;
148*54fd6939SJiyong Park 	}
149*54fd6939SJiyong Park }
150*54fd6939SJiyong Park 
151*54fd6939SJiyong Park /*
152*54fd6939SJiyong Park  * Allocate a buffer big enough to store the content of the specified file and
153*54fd6939SJiyong Park  * load the file into it. Fill 'size' with the file size. Exit the program on
154*54fd6939SJiyong Park  * error.
155*54fd6939SJiyong Park  */
load_file(const char * path,void ** ptr,uint32_t * size)156*54fd6939SJiyong Park static void load_file(const char *path, void **ptr, uint32_t *size)
157*54fd6939SJiyong Park {
158*54fd6939SJiyong Park 	FILE *f = fopen(path, "rb");
159*54fd6939SJiyong Park 	if (f == NULL) {
160*54fd6939SJiyong Park 		fprintf(stderr, "error: %s couldn't be opened.\n", path);
161*54fd6939SJiyong Park 		exit(1);
162*54fd6939SJiyong Park 	}
163*54fd6939SJiyong Park 
164*54fd6939SJiyong Park 	xfseek(f, 0, SEEK_END);
165*54fd6939SJiyong Park 	*size = ftell(f);
166*54fd6939SJiyong Park 	if (*size == 0) {
167*54fd6939SJiyong Park 		fprintf(stderr, "error: Size of %s is 0\n", path);
168*54fd6939SJiyong Park 		exit(1);
169*54fd6939SJiyong Park 	}
170*54fd6939SJiyong Park 
171*54fd6939SJiyong Park 	rewind(f);
172*54fd6939SJiyong Park 
173*54fd6939SJiyong Park 	*ptr = malloc(*size);
174*54fd6939SJiyong Park 	if (*ptr == NULL) {
175*54fd6939SJiyong Park 		fprintf(stderr, "error: Not enough memory to load %s\n", path);
176*54fd6939SJiyong Park 		exit(1);
177*54fd6939SJiyong Park 	}
178*54fd6939SJiyong Park 
179*54fd6939SJiyong Park 	if (fread(*ptr, *size, 1, f) != 1) {
180*54fd6939SJiyong Park 		fprintf(stderr, "error: Couldn't read %s\n", path);
181*54fd6939SJiyong Park 		exit(1);
182*54fd6939SJiyong Park 	}
183*54fd6939SJiyong Park 
184*54fd6939SJiyong Park 	fclose(f);
185*54fd6939SJiyong Park }
186*54fd6939SJiyong Park 
187*54fd6939SJiyong Park /*
188*54fd6939SJiyong Park  * Parse the string containing input payloads and fill in the
189*54fd6939SJiyong Park  * SP Package data structure.
190*54fd6939SJiyong Park  */
load_sp_pm(char * path,struct sp_pkg_info ** sp_out)191*54fd6939SJiyong Park static void load_sp_pm(char *path, struct sp_pkg_info **sp_out)
192*54fd6939SJiyong Park {
193*54fd6939SJiyong Park 	struct sp_pkg_info *sp_pkg;
194*54fd6939SJiyong Park 
195*54fd6939SJiyong Park 	char *split_mark = strstr(path, ":");
196*54fd6939SJiyong Park 
197*54fd6939SJiyong Park 	*split_mark = '\0';
198*54fd6939SJiyong Park 
199*54fd6939SJiyong Park 	char *sp_path = path;
200*54fd6939SJiyong Park 	char *pm_path = split_mark + 1;
201*54fd6939SJiyong Park 
202*54fd6939SJiyong Park 	sp_pkg = xzalloc(sizeof(struct sp_pkg_info),
203*54fd6939SJiyong Park 		"Failed to allocate sp_pkg_info struct");
204*54fd6939SJiyong Park 
205*54fd6939SJiyong Park 	load_file(pm_path, &sp_pkg->pm_data, &sp_pkg->pm_size);
206*54fd6939SJiyong Park 	printf("\nLoaded SP Manifest file %s (%u bytes)\n", pm_path, sp_pkg->pm_size);
207*54fd6939SJiyong Park 
208*54fd6939SJiyong Park 	load_file(sp_path, &sp_pkg->img_data, &sp_pkg->img_size);
209*54fd6939SJiyong Park 	printf("Loaded SP Image file %s (%u bytes)\n", sp_path, sp_pkg->img_size);
210*54fd6939SJiyong Park 
211*54fd6939SJiyong Park 	*sp_out = sp_pkg;
212*54fd6939SJiyong Park }
213*54fd6939SJiyong Park 
214*54fd6939SJiyong Park /*
215*54fd6939SJiyong Park  * Write SP package data structure into output file.
216*54fd6939SJiyong Park  */
output_write(const char * path,struct sp_pkg_info * sp,bool header)217*54fd6939SJiyong Park static void output_write(const char *path, struct sp_pkg_info *sp, bool header)
218*54fd6939SJiyong Park {
219*54fd6939SJiyong Park 	struct sp_pkg_header sp_header_info;
220*54fd6939SJiyong Park 	unsigned int file_ptr = 0;
221*54fd6939SJiyong Park 
222*54fd6939SJiyong Park 	FILE *f = fopen(path, "wb");
223*54fd6939SJiyong Park 	if (f == NULL) {
224*54fd6939SJiyong Park 		fprintf(stderr, "error: Failed to open %s\n", path);
225*54fd6939SJiyong Park 		exit(1);
226*54fd6939SJiyong Park 	}
227*54fd6939SJiyong Park 
228*54fd6939SJiyong Park 	/* Reserve Header size */
229*54fd6939SJiyong Park 	if (header) {
230*54fd6939SJiyong Park 		file_ptr = sizeof(struct sp_pkg_header);
231*54fd6939SJiyong Park 	}
232*54fd6939SJiyong Park 
233*54fd6939SJiyong Park 	/* Save partition manifest */
234*54fd6939SJiyong Park 	xfseek(f, file_ptr, SEEK_SET);
235*54fd6939SJiyong Park 	printf("Writing SP Manifest at offset 0x%x (%u bytes)\n",
236*54fd6939SJiyong Park 	       file_ptr, sp->pm_size);
237*54fd6939SJiyong Park 
238*54fd6939SJiyong Park 	sp->pm_offset = file_ptr;
239*54fd6939SJiyong Park 	xfwrite(sp->pm_data, sp->pm_size, f);
240*54fd6939SJiyong Park 
241*54fd6939SJiyong Park 	/* Save partition image aligned to Page size */
242*54fd6939SJiyong Park 	file_ptr = align_to((sp->pm_offset + sp->pm_size), PAGE_SIZE);
243*54fd6939SJiyong Park 	xfseek(f, file_ptr, SEEK_SET);
244*54fd6939SJiyong Park 	printf("Writing SP Image at offset 0x%x (%u bytes)\n",
245*54fd6939SJiyong Park 	       file_ptr, sp->img_size);
246*54fd6939SJiyong Park 
247*54fd6939SJiyong Park 	sp->img_offset = file_ptr;
248*54fd6939SJiyong Park 	xfwrite(sp->img_data, sp->img_size, f);
249*54fd6939SJiyong Park 
250*54fd6939SJiyong Park 	/* Finally, write header, if needed */
251*54fd6939SJiyong Park 	if (header) {
252*54fd6939SJiyong Park 		sp_header_info.magic = SECURE_PARTITION_MAGIC;
253*54fd6939SJiyong Park 		sp_header_info.version = 0x1;
254*54fd6939SJiyong Park 		sp_header_info.img_offset = sp->img_offset;
255*54fd6939SJiyong Park 		sp_header_info.img_size = sp->img_size;
256*54fd6939SJiyong Park 		sp_header_info.pm_offset = sp->pm_offset;
257*54fd6939SJiyong Park 		sp_header_info.pm_size = sp->pm_size;
258*54fd6939SJiyong Park 
259*54fd6939SJiyong Park 		xfseek(f, 0, SEEK_SET);
260*54fd6939SJiyong Park 
261*54fd6939SJiyong Park 		printf("Writing package header\n");
262*54fd6939SJiyong Park 
263*54fd6939SJiyong Park 		xfwrite(&sp_header_info, sizeof(struct sp_pkg_header), f);
264*54fd6939SJiyong Park 	}
265*54fd6939SJiyong Park 
266*54fd6939SJiyong Park 	/* All information has been written now */
267*54fd6939SJiyong Park 	printf("\nsptool: Built Secure Partition blob %s\n", path);
268*54fd6939SJiyong Park 
269*54fd6939SJiyong Park 	fclose(f);
270*54fd6939SJiyong Park }
271*54fd6939SJiyong Park 
usage(void)272*54fd6939SJiyong Park static void usage(void)
273*54fd6939SJiyong Park {
274*54fd6939SJiyong Park 	printf("usage: sptool ");
275*54fd6939SJiyong Park #ifdef VERSION
276*54fd6939SJiyong Park 	printf(VERSION);
277*54fd6939SJiyong Park #else
278*54fd6939SJiyong Park 	/* If built from sptool directory, VERSION is not set. */
279*54fd6939SJiyong Park 	printf("version unknown");
280*54fd6939SJiyong Park #endif
281*54fd6939SJiyong Park 	printf(" [<args>]\n\n");
282*54fd6939SJiyong Park 
283*54fd6939SJiyong Park 	printf("This tool takes as input set of image binary files and the\n"
284*54fd6939SJiyong Park 	       "partition manifest blobs as input and generates set of\n"
285*54fd6939SJiyong Park 	       "output package files\n"
286*54fd6939SJiyong Park 	       "Usage example: sptool -i sp1.bin:sp1.dtb -o sp1.pkg\n"
287*54fd6939SJiyong Park 	       "                      -i sp2.bin:sp2.dtb -o sp2.pkg ...\n\n");
288*54fd6939SJiyong Park 	printf("Commands supported:\n");
289*54fd6939SJiyong Park 	printf("  -o <path>            Set output file path.\n");
290*54fd6939SJiyong Park 	printf("  -i <sp_path:pm_path> Add Secure Partition image and\n"
291*54fd6939SJiyong Park 	       "                       Manifest blob (specified in two paths\n"
292*54fd6939SJiyong Park 	       "                       separated by a colon).\n");
293*54fd6939SJiyong Park 	printf("  -n                   Generate package without header\n");
294*54fd6939SJiyong Park 	printf("  -h                   Show this message.\n");
295*54fd6939SJiyong Park 	exit(1);
296*54fd6939SJiyong Park }
297*54fd6939SJiyong Park 
main(int argc,char * argv[])298*54fd6939SJiyong Park int main(int argc, char *argv[])
299*54fd6939SJiyong Park {
300*54fd6939SJiyong Park 	struct sp_pkg_info *sp_pkg = NULL;
301*54fd6939SJiyong Park 	struct arg_list *in_head = NULL;
302*54fd6939SJiyong Park 	struct arg_list *out_head = NULL;
303*54fd6939SJiyong Park 	struct arg_list *in_list = NULL;
304*54fd6939SJiyong Park 	struct arg_list *out_list = NULL;
305*54fd6939SJiyong Park 	unsigned int match_counter = 0;
306*54fd6939SJiyong Park 	bool need_header = true;
307*54fd6939SJiyong Park 
308*54fd6939SJiyong Park 	int ch;
309*54fd6939SJiyong Park 
310*54fd6939SJiyong Park 	if (argc <= 1) {
311*54fd6939SJiyong Park 		fprintf(stderr, "error: File paths must be provided.\n\n");
312*54fd6939SJiyong Park 		usage();
313*54fd6939SJiyong Park 		return 1;
314*54fd6939SJiyong Park 	}
315*54fd6939SJiyong Park 
316*54fd6939SJiyong Park 	while ((ch = getopt(argc, argv, "hni:o:")) != -1) {
317*54fd6939SJiyong Park 		switch (ch) {
318*54fd6939SJiyong Park 		case 'i':
319*54fd6939SJiyong Park 			append_user_input(&in_head, optarg);
320*54fd6939SJiyong Park 			match_counter++;
321*54fd6939SJiyong Park 			break;
322*54fd6939SJiyong Park 		case 'o':
323*54fd6939SJiyong Park 			append_user_input(&out_head, optarg);
324*54fd6939SJiyong Park 			match_counter--;
325*54fd6939SJiyong Park 			break;
326*54fd6939SJiyong Park 		case 'n':
327*54fd6939SJiyong Park 			need_header = false;
328*54fd6939SJiyong Park 			break;
329*54fd6939SJiyong Park 		case 'h':
330*54fd6939SJiyong Park 		default:
331*54fd6939SJiyong Park 			usage();
332*54fd6939SJiyong Park 		}
333*54fd6939SJiyong Park 	}
334*54fd6939SJiyong Park 
335*54fd6939SJiyong Park 	if (match_counter) {
336*54fd6939SJiyong Park 		fprintf(stderr, "error: Input/Output count mismatch.\n\n");
337*54fd6939SJiyong Park 		freelist(in_head);
338*54fd6939SJiyong Park 		freelist(out_head);
339*54fd6939SJiyong Park 		usage();
340*54fd6939SJiyong Park 		return 1;
341*54fd6939SJiyong Park 	}
342*54fd6939SJiyong Park 
343*54fd6939SJiyong Park 	in_list = in_head;
344*54fd6939SJiyong Park 	out_list = out_head;
345*54fd6939SJiyong Park 	while (in_list != NULL) {
346*54fd6939SJiyong Park 		load_sp_pm(in_list->usr_input, &sp_pkg);
347*54fd6939SJiyong Park 		output_write(out_list->usr_input, sp_pkg, need_header);
348*54fd6939SJiyong Park 		in_list = in_list->next;
349*54fd6939SJiyong Park 		out_list = out_list->next;
350*54fd6939SJiyong Park 	}
351*54fd6939SJiyong Park 
352*54fd6939SJiyong Park 	argc -= optind;
353*54fd6939SJiyong Park 	argv += optind;
354*54fd6939SJiyong Park 
355*54fd6939SJiyong Park 	cleanup(sp_pkg);
356*54fd6939SJiyong Park 	freelist(in_head);
357*54fd6939SJiyong Park 	freelist(out_head);
358*54fd6939SJiyong Park 
359*54fd6939SJiyong Park 	return 0;
360*54fd6939SJiyong Park }
361