blob: 38baa2cd9996a1df17dcc4fdda5d77a2c7d6f46b [file] [log] [blame]
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +00001/*
Manish Pandey7ace7842020-01-07 17:05:28 +00002 * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +00003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <stdarg.h>
Manish Pandey7ace7842020-01-07 17:05:28 +00008#include <stdbool.h>
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +00009#include <stdint.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
14
15#include "sptool.h"
16
17#define PAGE_SIZE 4096
18
19/*
Manish Pandey7ace7842020-01-07 17:05:28 +000020 * Entry describing Secure Partition package.
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +000021 */
Manish Pandey7ace7842020-01-07 17:05:28 +000022struct sp_pkg_info {
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +000023 /* Location of the files in the host's RAM. */
Manish Pandey7ace7842020-01-07 17:05:28 +000024 void *img_data, *pm_data;
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +000025
26 /* Size of the files. */
Manish Pandey7ace7842020-01-07 17:05:28 +000027 uint32_t img_size, pm_size;
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +000028
29 /* Location of the binary files inside the package output file */
Manish Pandey7ace7842020-01-07 17:05:28 +000030 uint32_t img_offset, pm_offset;
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +000031};
32
Manish Pandey7ace7842020-01-07 17:05:28 +000033/*
34 * List of input provided by user
35 */
36struct arg_list {
37 char *usr_input;
38 struct arg_list *next;
39};
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +000040
41/* Align an address to a power-of-two boundary. */
42static unsigned int align_to(unsigned int address, unsigned int boundary)
43{
44 unsigned int mask = boundary - 1U;
45
46 if ((address & mask) != 0U)
47 return (address + boundary) & ~mask;
48 else
49 return address;
50}
51
52/* Allocate a memory area of 'size' bytes and zero it. */
53static void *xzalloc(size_t size, const char *msg)
54{
55 void *d;
56
57 d = malloc(size);
58 if (d == NULL) {
59 fprintf(stderr, "error: malloc: %s\n", msg);
60 exit(1);
61 }
62
63 memset(d, 0, size);
64
65 return d;
66}
67
68/*
69 * Write 'size' bytes from 'buf' into the specified file stream.
70 * Exit the program on error.
71 */
72static void xfwrite(void *buf, size_t size, FILE *fp)
73{
74 if (fwrite(buf, 1, size, fp) != size) {
75 fprintf(stderr, "error: Failed to write to output file.\n");
76 exit(1);
77 }
78}
79
80/*
81 * Set the file position indicator for the specified file stream.
82 * Exit the program on error.
83 */
84static void xfseek(FILE *fp, long offset, int whence)
85{
86 if (fseek(fp, offset, whence) != 0) {
87 fprintf(stderr, "error: Failed to set file to offset 0x%lx (%d).\n",
88 offset, whence);
89 perror(NULL);
90 exit(1);
91 }
92}
93
Manish Pandey7ace7842020-01-07 17:05:28 +000094/*
95 * Free SP package structure
96 */
97static void cleanup(struct sp_pkg_info *sp)
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +000098{
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +000099
Manish Pandey7ace7842020-01-07 17:05:28 +0000100 if (sp != NULL) {
101 if (sp->img_data != NULL) {
102 free(sp->img_data);
103 }
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000104
Manish Pandey7ace7842020-01-07 17:05:28 +0000105 if (sp->pm_data != NULL) {
106 free(sp->pm_data);
107 }
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000108
109 free(sp);
110
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000111 }
Manish Pandey7ace7842020-01-07 17:05:28 +0000112}
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000113
Manish Pandey7ace7842020-01-07 17:05:28 +0000114/*
115 * Free argument list structure
116 */
117static void freelist(struct arg_list *head)
118{
119 struct arg_list *tmp;
120
121 while (head != NULL) {
122 tmp = head;
123 head = head->next;
124 free(tmp);
125 }
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000126}
127
128/*
Manish Pandey7ace7842020-01-07 17:05:28 +0000129 * Append user inputs in argument list structure
130 */
131static void append_user_input(struct arg_list **head, char *args)
132{
133 struct arg_list *tmp = *head;
134
135 if (tmp == NULL) {
136 tmp = xzalloc(sizeof(struct arg_list),
137 "Failed to allocate arg_list struct");
138 tmp->usr_input = args;
139 *head = tmp;
140 } else {
141 while (tmp->next != NULL) {
142 tmp = tmp->next;
143 }
144 tmp->next = xzalloc(sizeof(struct arg_list),
145 "Failed to allocate arg_list struct");
146 tmp = tmp->next;
147 tmp->usr_input = args;
148 }
149}
150
151/*
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000152 * Allocate a buffer big enough to store the content of the specified file and
153 * load the file into it. Fill 'size' with the file size. Exit the program on
154 * error.
155 */
Manish Pandey7ace7842020-01-07 17:05:28 +0000156static void load_file(const char *path, void **ptr, uint32_t *size)
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000157{
158 FILE *f = fopen(path, "rb");
159 if (f == NULL) {
160 fprintf(stderr, "error: %s couldn't be opened.\n", path);
161 exit(1);
162 }
163
164 xfseek(f, 0, SEEK_END);
165 *size = ftell(f);
166 if (*size == 0) {
167 fprintf(stderr, "error: Size of %s is 0\n", path);
168 exit(1);
169 }
170
171 rewind(f);
172
173 *ptr = malloc(*size);
174 if (*ptr == NULL) {
175 fprintf(stderr, "error: Not enough memory to load %s\n", path);
176 exit(1);
177 }
178
179 if (fread(*ptr, *size, 1, f) != 1) {
180 fprintf(stderr, "error: Couldn't read %s\n", path);
181 exit(1);
182 }
183
184 fclose(f);
185}
186
Manish Pandey7ace7842020-01-07 17:05:28 +0000187/*
188 * Parse the string containing input payloads and fill in the
189 * SP Package data structure.
190 */
191static void load_sp_pm(char *path, struct sp_pkg_info **sp_out)
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000192{
Manish Pandey7ace7842020-01-07 17:05:28 +0000193 struct sp_pkg_info *sp_pkg;
194
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000195 char *split_mark = strstr(path, ":");
196
197 *split_mark = '\0';
198
199 char *sp_path = path;
Manish Pandey7ace7842020-01-07 17:05:28 +0000200 char *pm_path = split_mark + 1;
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000201
Manish Pandey7ace7842020-01-07 17:05:28 +0000202 sp_pkg = xzalloc(sizeof(struct sp_pkg_info),
203 "Failed to allocate sp_pkg_info struct");
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000204
Manish Pandey7ace7842020-01-07 17:05:28 +0000205 load_file(pm_path, &sp_pkg->pm_data, &sp_pkg->pm_size);
206 printf("\nLoaded SP Manifest file %s (%u bytes)\n", pm_path, sp_pkg->pm_size);
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000207
Manish Pandey7ace7842020-01-07 17:05:28 +0000208 load_file(sp_path, &sp_pkg->img_data, &sp_pkg->img_size);
209 printf("Loaded SP Image file %s (%u bytes)\n", sp_path, sp_pkg->img_size);
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000210
Manish Pandey7ace7842020-01-07 17:05:28 +0000211 *sp_out = sp_pkg;
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000212}
213
Manish Pandey7ace7842020-01-07 17:05:28 +0000214/*
215 * Write SP package data structure into output file.
216 */
217static void output_write(const char *path, struct sp_pkg_info *sp, bool header)
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000218{
Manish Pandey7ace7842020-01-07 17:05:28 +0000219 struct sp_pkg_header sp_header_info;
220 unsigned int file_ptr = 0;
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000221
222 FILE *f = fopen(path, "wb");
223 if (f == NULL) {
224 fprintf(stderr, "error: Failed to open %s\n", path);
225 exit(1);
226 }
227
Manish Pandey7ace7842020-01-07 17:05:28 +0000228 /* Reserve Header size */
229 if (header) {
230 file_ptr = sizeof(struct sp_pkg_header);
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000231 }
232
Manish Pandey7ace7842020-01-07 17:05:28 +0000233 /* Save partition manifest */
234 xfseek(f, file_ptr, SEEK_SET);
235 printf("Writing SP Manifest at offset 0x%x (%u bytes)\n",
236 file_ptr, sp->pm_size);
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000237
Manish Pandey7ace7842020-01-07 17:05:28 +0000238 sp->pm_offset = file_ptr;
239 xfwrite(sp->pm_data, sp->pm_size, f);
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000240
Manish Pandey7ace7842020-01-07 17:05:28 +0000241 /* Save partition image aligned to Page size */
242 file_ptr = align_to((sp->pm_offset + sp->pm_size), PAGE_SIZE);
243 xfseek(f, file_ptr, SEEK_SET);
244 printf("Writing SP Image at offset 0x%x (%u bytes)\n",
245 file_ptr, sp->img_size);
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000246
Manish Pandey7ace7842020-01-07 17:05:28 +0000247 sp->img_offset = file_ptr;
248 xfwrite(sp->img_data, sp->img_size, f);
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000249
Manish Pandey7ace7842020-01-07 17:05:28 +0000250 /* Finally, write header, if needed */
251 if (header) {
252 sp_header_info.magic = SECURE_PARTITION_MAGIC;
253 sp_header_info.version = 0x1;
254 sp_header_info.img_offset = sp->img_offset;
255 sp_header_info.img_size = sp->img_size;
256 sp_header_info.pm_offset = sp->pm_offset;
257 sp_header_info.pm_size = sp->pm_size;
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000258
Manish Pandey7ace7842020-01-07 17:05:28 +0000259 xfseek(f, 0, SEEK_SET);
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000260
Manish Pandey7ace7842020-01-07 17:05:28 +0000261 printf("Writing package header\n");
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000262
Manish Pandey7ace7842020-01-07 17:05:28 +0000263 xfwrite(&sp_header_info, sizeof(struct sp_pkg_header), f);
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000264 }
265
266 /* All information has been written now */
Manish Pandey7ace7842020-01-07 17:05:28 +0000267 printf("\nsptool: Built Secure Partition blob %s\n", path);
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000268
269 fclose(f);
270}
271
272static void usage(void)
273{
274 printf("usage: sptool ");
275#ifdef VERSION
276 printf(VERSION);
277#else
278 /* If built from sptool directory, VERSION is not set. */
279 printf("version unknown");
280#endif
281 printf(" [<args>]\n\n");
282
Manish Pandey7ace7842020-01-07 17:05:28 +0000283 printf("This tool takes as input set of image binary files and the\n"
284 "partition manifest blobs as input and generates set of\n"
285 "output package files\n"
286 "Usage example: sptool -i sp1.bin:sp1.dtb -o sp1.pkg\n"
287 " -i sp2.bin:sp2.dtb -o sp2.pkg ...\n\n");
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000288 printf("Commands supported:\n");
289 printf(" -o <path> Set output file path.\n");
Manish Pandey7ace7842020-01-07 17:05:28 +0000290 printf(" -i <sp_path:pm_path> Add Secure Partition image and\n"
291 " Manifest blob (specified in two paths\n"
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000292 " separated by a colon).\n");
Manish Pandey7ace7842020-01-07 17:05:28 +0000293 printf(" -n Generate package without header\n");
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000294 printf(" -h Show this message.\n");
295 exit(1);
296}
297
298int main(int argc, char *argv[])
299{
Manish Pandey7ace7842020-01-07 17:05:28 +0000300 struct sp_pkg_info *sp_pkg = NULL;
301 struct arg_list *in_head = NULL;
302 struct arg_list *out_head = NULL;
303 struct arg_list *in_list = NULL;
304 struct arg_list *out_list = NULL;
305 unsigned int match_counter = 0;
306 bool need_header = true;
307
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000308 int ch;
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000309
Manish Pandey7ace7842020-01-07 17:05:28 +0000310 if (argc <= 1) {
311 fprintf(stderr, "error: File paths must be provided.\n\n");
312 usage();
313 return 1;
314 }
315
316 while ((ch = getopt(argc, argv, "hni:o:")) != -1) {
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000317 switch (ch) {
318 case 'i':
Manish Pandey7ace7842020-01-07 17:05:28 +0000319 append_user_input(&in_head, optarg);
320 match_counter++;
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000321 break;
322 case 'o':
Manish Pandey7ace7842020-01-07 17:05:28 +0000323 append_user_input(&out_head, optarg);
324 match_counter--;
325 break;
326 case 'n':
327 need_header = false;
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000328 break;
329 case 'h':
330 default:
331 usage();
332 }
333 }
334
Manish Pandey7ace7842020-01-07 17:05:28 +0000335 if (match_counter) {
336 fprintf(stderr, "error: Input/Output count mismatch.\n\n");
337 freelist(in_head);
338 freelist(out_head);
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000339 usage();
340 return 1;
341 }
342
Manish Pandey7ace7842020-01-07 17:05:28 +0000343 in_list = in_head;
344 out_list = out_head;
345 while (in_list != NULL) {
346 load_sp_pm(in_list->usr_input, &sp_pkg);
347 output_write(out_list->usr_input, sp_pkg, need_header);
348 in_list = in_list->next;
349 out_list = out_list->next;
350 }
351
352 argc -= optind;
353 argv += optind;
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000354
Manish Pandey7ace7842020-01-07 17:05:28 +0000355 cleanup(sp_pkg);
356 freelist(in_head);
357 freelist(out_head);
Antonio Nino Diaza830a4d2018-11-27 14:58:04 +0000358
359 return 0;
360}