• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2018, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdarg.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 
14 #include "sptool.h"
15 
16 #define PAGE_SIZE		4096
17 
18 /*
19  * Linked list of entries describing entries in the secure
20  * partition package.
21  */
22 struct sp_entry_info {
23 	/* Location of the files in the host's RAM. */
24 	void *sp_data, *rd_data;
25 
26 	/* Size of the files. */
27 	uint64_t sp_size, rd_size;
28 
29 	/* Location of the binary files inside the package output file */
30 	uint64_t sp_offset, rd_offset;
31 
32 	struct sp_entry_info *next;
33 };
34 
35 static struct sp_entry_info *sp_info_head;
36 
37 static uint64_t sp_count;
38 
39 /* Align an address to a power-of-two boundary. */
align_to(unsigned int address,unsigned int boundary)40 static unsigned int align_to(unsigned int address, unsigned int boundary)
41 {
42 	unsigned int mask = boundary - 1U;
43 
44 	if ((address & mask) != 0U)
45 		return (address + boundary) & ~mask;
46 	else
47 		return address;
48 }
49 
50 /* Allocate a memory area of 'size' bytes and zero it. */
xzalloc(size_t size,const char * msg)51 static void *xzalloc(size_t size, const char *msg)
52 {
53 	void *d;
54 
55 	d = malloc(size);
56 	if (d == NULL) {
57 		fprintf(stderr, "error: malloc: %s\n", msg);
58 		exit(1);
59 	}
60 
61 	memset(d, 0, size);
62 
63 	return d;
64 }
65 
66 /*
67  * Write 'size' bytes from 'buf' into the specified file stream.
68  * Exit the program on error.
69  */
xfwrite(void * buf,size_t size,FILE * fp)70 static void xfwrite(void *buf, size_t size, FILE *fp)
71 {
72 	if (fwrite(buf, 1, size, fp) != size) {
73 		fprintf(stderr, "error: Failed to write to output file.\n");
74 		exit(1);
75 	}
76 }
77 
78 /*
79  * Set the file position indicator for the specified file stream.
80  * Exit the program on error.
81  */
xfseek(FILE * fp,long offset,int whence)82 static void xfseek(FILE *fp, long offset, int whence)
83 {
84 	if (fseek(fp, offset, whence) != 0) {
85 		fprintf(stderr, "error: Failed to set file to offset 0x%lx (%d).\n",
86 		       offset, whence);
87 		perror(NULL);
88 		exit(1);
89 	}
90 }
91 
cleanup(void)92 static void cleanup(void)
93 {
94 	struct sp_entry_info *sp = sp_info_head;
95 
96 	while (sp != NULL) {
97 		struct sp_entry_info *next = sp->next;
98 
99 		if (sp->sp_data != NULL)
100 			free(sp->sp_data);
101 
102 		if (sp->rd_data != NULL)
103 			free(sp->rd_data);
104 
105 		free(sp);
106 
107 		sp = next;
108 	}
109 
110 	sp_count = 0;
111 	sp_info_head = NULL;
112 }
113 
114 /*
115  * Allocate a buffer big enough to store the content of the specified file and
116  * load the file into it. Fill 'size' with the file size. Exit the program on
117  * error.
118  */
load_file(const char * path,void ** ptr,uint64_t * size)119 static void load_file(const char *path, void **ptr, uint64_t *size)
120 {
121 	FILE *f = fopen(path, "rb");
122 	if (f == NULL) {
123 		fprintf(stderr, "error: %s couldn't be opened.\n", path);
124 		exit(1);
125 	}
126 
127 	xfseek(f, 0, SEEK_END);
128 	*size = ftell(f);
129 	if (*size == 0) {
130 		fprintf(stderr, "error: Size of %s is 0\n", path);
131 		exit(1);
132 	}
133 
134 	rewind(f);
135 
136 	*ptr = malloc(*size);
137 	if (*ptr == NULL) {
138 		fprintf(stderr, "error: Not enough memory to load %s\n", path);
139 		exit(1);
140 	}
141 
142 	if (fread(*ptr, *size, 1, f) != 1) {
143 		fprintf(stderr, "error: Couldn't read %s\n", path);
144 		exit(1);
145 	}
146 
147 	fclose(f);
148 }
149 
load_sp_rd(char * path)150 static void load_sp_rd(char *path)
151 {
152 	char *split_mark = strstr(path, ":");
153 
154 	*split_mark = '\0';
155 
156 	char *sp_path = path;
157 	char *rd_path = split_mark + 1;
158 
159 	struct sp_entry_info *sp;
160 
161 	if (sp_info_head == NULL) {
162 		sp_info_head = xzalloc(sizeof(struct sp_entry_info),
163 			"Failed to allocate sp_entry_info struct");
164 
165 		sp = sp_info_head;
166 	} else {
167 		sp = sp_info_head;
168 
169 		while (sp->next != NULL) {
170 			sp = sp->next;
171 		}
172 
173 		sp->next = xzalloc(sizeof(struct sp_entry_info),
174 			"Failed to allocate sp_entry_info struct");
175 
176 		sp = sp->next;
177 	}
178 
179 	load_file(sp_path, &sp->sp_data, &sp->sp_size);
180 	printf("Loaded image file %s (%lu bytes)\n", sp_path, sp->sp_size);
181 
182 	load_file(rd_path, &sp->rd_data, &sp->rd_size);
183 	printf("Loaded RD file %s (%lu bytes)\n", rd_path, sp->rd_size);
184 
185 	sp_count++;
186 }
187 
output_write(const char * path)188 static void output_write(const char *path)
189 {
190 	struct sp_entry_info *sp;
191 
192 	if (sp_count == 0) {
193 		fprintf(stderr, "error: At least one SP must be provided.\n");
194 		exit(1);
195 	}
196 
197 	/* The layout of the structs is specified in the header file sptool.h */
198 
199 	printf("Writing %lu partitions to output file.\n", sp_count);
200 
201 	unsigned int header_size = (sizeof(struct sp_pkg_header) * 8)
202 				 + (sizeof(struct sp_pkg_entry) * 8 * sp_count);
203 
204 	FILE *f = fopen(path, "wb");
205 	if (f == NULL) {
206 		fprintf(stderr, "error: Failed to open %s\n", path);
207 		exit(1);
208 	}
209 
210 	unsigned int file_ptr = align_to(header_size, PAGE_SIZE);
211 
212 	/* First, save all partition images aligned to page boundaries */
213 
214 	sp = sp_info_head;
215 
216 	for (uint64_t i = 0; i < sp_count; i++) {
217 		xfseek(f, file_ptr, SEEK_SET);
218 
219 		printf("Writing image %lu to offset 0x%x (0x%lx bytes)\n",
220 		       i, file_ptr, sp->sp_size);
221 
222 		sp->sp_offset = file_ptr;
223 		xfwrite(sp->sp_data, sp->sp_size, f);
224 		file_ptr = align_to(file_ptr + sp->sp_size, PAGE_SIZE);
225 		sp = sp->next;
226 	}
227 
228 	/* Now, save resource description blobs aligned to 8 bytes */
229 
230 	sp = sp_info_head;
231 
232 	for (uint64_t i = 0; i < sp_count; i++) {
233 		xfseek(f, file_ptr, SEEK_SET);
234 
235 		printf("Writing RD blob %lu to offset 0x%x (0x%lx bytes)\n",
236 		       i, file_ptr, sp->rd_size);
237 
238 		sp->rd_offset = file_ptr;
239 		xfwrite(sp->rd_data, sp->rd_size, f);
240 		file_ptr = align_to(file_ptr + sp->rd_size, 8);
241 		sp = sp->next;
242 	}
243 
244 	/* Finally, write header */
245 
246 	uint64_t version = 0x1;
247 	uint64_t sp_num = sp_count;
248 
249 	xfseek(f, 0, SEEK_SET);
250 
251 	xfwrite(&version, sizeof(uint64_t), f);
252 	xfwrite(&sp_num, sizeof(uint64_t), f);
253 
254 	sp = sp_info_head;
255 
256 	for (unsigned int i = 0; i < sp_count; i++) {
257 
258 		uint64_t sp_offset, sp_size, rd_offset, rd_size;
259 
260 		sp_offset = sp->sp_offset;
261 		sp_size = align_to(sp->sp_size, PAGE_SIZE);
262 		rd_offset = sp->rd_offset;
263 		rd_size = sp->rd_size;
264 
265 		xfwrite(&sp_offset, sizeof(uint64_t), f);
266 		xfwrite(&sp_size, sizeof(uint64_t), f);
267 		xfwrite(&rd_offset, sizeof(uint64_t), f);
268 		xfwrite(&rd_size, sizeof(uint64_t), f);
269 
270 		sp = sp->next;
271 	}
272 
273 	/* All information has been written now */
274 
275 	fclose(f);
276 }
277 
usage(void)278 static void usage(void)
279 {
280 	printf("usage: sptool ");
281 #ifdef VERSION
282 	printf(VERSION);
283 #else
284 	/* If built from sptool directory, VERSION is not set. */
285 	printf("version unknown");
286 #endif
287 	printf(" [<args>]\n\n");
288 
289 	printf("This tool takes as inputs several image binary files and the\n"
290 	       "resource description blobs as input and generates a package\n"
291 	       "file that contains them.\n\n");
292 	printf("Commands supported:\n");
293 	printf("  -o <path>            Set output file path.\n");
294 	printf("  -i <sp_path:rd_path> Add Secure Partition image and Resource\n"
295 	       "                       Description blob (specified in two paths\n"
296 	       "                       separated by a colon).\n");
297 	printf("  -h                   Show this message.\n");
298 	exit(1);
299 }
300 
main(int argc,char * argv[])301 int main(int argc, char *argv[])
302 {
303 	int ch;
304 	const char *outname = NULL;
305 
306 	while ((ch = getopt(argc, argv, "hi:o:")) != -1) {
307 		switch (ch) {
308 		case 'i':
309 			load_sp_rd(optarg);
310 			break;
311 		case 'o':
312 			outname = optarg;
313 			break;
314 		case 'h':
315 		default:
316 			usage();
317 		}
318 	}
319 
320 	argc -= optind;
321 	argv += optind;
322 
323 	if (outname == NULL) {
324 		fprintf(stderr, "error: An output file path must be provided.\n\n");
325 		usage();
326 		return 1;
327 	}
328 
329 	output_write(outname);
330 
331 	cleanup();
332 
333 	return 0;
334 }
335