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