1331722Seadler// SPDX-License-Identifier: GPL-2.0+
2341477Svmaffione/*
3341477Svmaffione * Copyright (C) 2018 Xilinx, Inc.
4261909Sluigi */
5261909Sluigi
6261909Sluigi#include <common.h>
7261909Sluigi#include <command.h>
8261909Sluigi#include <log.h>
9261909Sluigi#include <asm/global_data.h>
10261909Sluigi#include <asm/io.h>
11261909Sluigi#include <asm/arch/hardware.h>
12261909Sluigi#include <asm/arch/sys_proto.h>
13261909Sluigi#include <malloc.h>
14261909Sluigi#include <linux/bitops.h>
15261909Sluigi#include <u-boot/md5.h>
16261909Sluigi#include <u-boot/rsa.h>
17261909Sluigi#include <u-boot/rsa-mod-exp.h>
18261909Sluigi#include <u-boot/sha256.h>
19261909Sluigi#include <zynqpl.h>
20261909Sluigi#include <fpga.h>
21261909Sluigi#include <zynq_bootimg.h>
22261909Sluigi
23261909SluigiDECLARE_GLOBAL_DATA_PTR;
24261909Sluigi
25261909Sluigi#ifdef CONFIG_CMD_ZYNQ_RSA
26261909Sluigi
27261909Sluigi#define ZYNQ_EFUSE_RSA_ENABLE_MASK	0x400
28261909Sluigi#define ZYNQ_ATTRIBUTE_PL_IMAGE_MASK		0x20
29261909Sluigi#define ZYNQ_ATTRIBUTE_CHECKSUM_TYPE_MASK	0x7000
30261909Sluigi#define ZYNQ_ATTRIBUTE_RSA_PRESENT_MASK		0x8000
31261909Sluigi#define ZYNQ_ATTRIBUTE_RSA_PART_OWNER_MASK	0x30000
32261909Sluigi
33261909Sluigi#define ZYNQ_RSA_MODULAR_SIZE			256
34261909Sluigi#define ZYNQ_RSA_MODULAR_EXT_SIZE		256
35261909Sluigi#define ZYNQ_RSA_EXPO_SIZE			64
36261909Sluigi#define ZYNQ_RSA_SPK_SIGNATURE_SIZE		256
37261909Sluigi#define ZYNQ_RSA_PARTITION_SIGNATURE_SIZE	256
38261909Sluigi#define ZYNQ_RSA_SIGNATURE_SIZE			0x6C0
39261909Sluigi#define ZYNQ_RSA_HEADER_SIZE			4
40261909Sluigi#define ZYNQ_RSA_MAGIC_WORD_SIZE		60
41261909Sluigi#define ZYNQ_RSA_PART_OWNER_UBOOT		1
42261909Sluigi#define ZYNQ_RSA_ALIGN_PPK_START		64
43261909Sluigi
44261909Sluigi#define WORD_LENGTH_SHIFT	2
45261909Sluigi
46261909Sluigistatic u8 *ppkmodular;
47261909Sluigistatic u8 *ppkmodularex;
48261909Sluigi
49261909Sluigistruct zynq_rsa_public_key {
50261909Sluigi	uint len;		/* Length of modulus[] in number of u32 */
51261909Sluigi	u32 n0inv;		/* -1 / modulus[0] mod 2^32 */
52261909Sluigi	u32 *modulus;	/* modulus as little endian array */
53261909Sluigi	u32 *rr;		/* R^2 as little endian array */
54261909Sluigi};
55261909Sluigi
56261909Sluigistatic struct zynq_rsa_public_key public_key;
57261909Sluigi
58341477Svmaffionestatic struct partition_hdr part_hdr[ZYNQ_MAX_PARTITION_NUMBER];
59341477Svmaffione
60341477Svmaffione/*
61261909Sluigi * Extract the primary public key components from already autheticated FSBL
62261909Sluigi */
63261909Sluigistatic void zynq_extract_ppk(u32 fsbl_len)
64261909Sluigi{
65261909Sluigi	u32 padsize;
66261909Sluigi	u8 *ppkptr;
67261909Sluigi
68261909Sluigi	debug("%s\n", __func__);
69261909Sluigi
70261909Sluigi	/*
71261909Sluigi	 * Extract the authenticated PPK from OCM i.e at end of the FSBL
72261909Sluigi	 */
73261909Sluigi	ppkptr = (u8 *)(fsbl_len + ZYNQ_OCM_BASEADDR);
74261909Sluigi	padsize = ((u32)ppkptr % ZYNQ_RSA_ALIGN_PPK_START);
75261909Sluigi	if (padsize)
76261909Sluigi		ppkptr += (ZYNQ_RSA_ALIGN_PPK_START - padsize);
77261909Sluigi
78341477Svmaffione	ppkptr += ZYNQ_RSA_HEADER_SIZE;
79261909Sluigi
80341477Svmaffione	ppkptr += ZYNQ_RSA_MAGIC_WORD_SIZE;
81341477Svmaffione
82261909Sluigi	ppkmodular = (u8 *)ppkptr;
83341477Svmaffione	ppkptr += ZYNQ_RSA_MODULAR_SIZE;
84341477Svmaffione	ppkmodularex = (u8 *)ppkptr;
85341477Svmaffione	ppkptr += ZYNQ_RSA_MODULAR_EXT_SIZE;
86261909Sluigi}
87261909Sluigi
88285349Sluigi/*
89285349Sluigi * Calculate the inverse(-1 / modulus[0] mod 2^32 ) for the PPK
90261909Sluigi */
91341477Svmaffionestatic u32 zynq_calc_inv(void)
92285349Sluigi{
93261909Sluigi	u32 modulus = public_key.modulus[0];
94285349Sluigi	u32 tmp = BIT(1);
95285349Sluigi	u32 inverse;
96261909Sluigi
97341477Svmaffione	inverse = modulus & BIT(0);
98285349Sluigi
99285349Sluigi	while (tmp) {
100261909Sluigi		inverse *= 2 - modulus * inverse;
101341477Svmaffione		tmp *= tmp;
102341477Svmaffione	}
103341477Svmaffione
104285349Sluigi	return ~(inverse - 1);
105261909Sluigi}
106261909Sluigi
107285349Sluigi/*
108261909Sluigi * Recreate the signature by padding the bytes and verify with hash value
109261909Sluigi */
110261909Sluigistatic int zynq_pad_and_check(u8 *signature, u8 *hash)
111261909Sluigi{
112261909Sluigi	u8 padding[] = {0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48,
113261909Sluigi			0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04,
114261909Sluigi			0x20};
115261909Sluigi	u8 *pad_ptr = signature + 256;
116261909Sluigi	u32 pad = 202;
117261909Sluigi	u32 ii;
118285349Sluigi
119285349Sluigi	/*
120285349Sluigi	 * Re-Create PKCS#1v1.5 Padding
121285349Sluigi	 * MSB  ----------------------------------------------------LSB
122341477Svmaffione	 * 0x0 || 0x1 || 0xFF(for 202 bytes) || 0x0 || T_padding || SHA256 Hash
123261909Sluigi	 */
124261909Sluigi	if (*--pad_ptr != 0 || *--pad_ptr != 1)
125261909Sluigi		return -1;
126261909Sluigi
127261909Sluigi	for (ii = 0; ii < pad; ii++) {
128261909Sluigi		if (*--pad_ptr != 0xFF)
129261909Sluigi			return -1;
130261909Sluigi	}
131341477Svmaffione
132261909Sluigi	if (*--pad_ptr != 0)
133261909Sluigi		return -1;
134261909Sluigi
135261909Sluigi	for (ii = 0; ii < sizeof(padding); ii++) {
136261909Sluigi		if (*--pad_ptr != padding[ii])
137341477Svmaffione			return -1;
138261909Sluigi	}
139341477Svmaffione
140341477Svmaffione	for (ii = 0; ii < 32; ii++) {
141341477Svmaffione		if (*--pad_ptr != hash[ii])
142341477Svmaffione			return -1;
143341477Svmaffione	}
144261909Sluigi	return 0;
145261909Sluigi}
146261909Sluigi
147261909Sluigi/*
148261909Sluigi * Verify and extract the hash value from signature using the public key
149261909Sluigi * and compare it with calculated hash value.
150261909Sluigi */
151261909Sluigistatic int zynq_rsa_verify_key(const struct zynq_rsa_public_key *key,
152261909Sluigi			       const u8 *sig, const u32 sig_len, const u8 *hash)
153261909Sluigi{
154261909Sluigi	int status;
155285349Sluigi	void *buf;
156285349Sluigi
157285349Sluigi	if (!key || !sig || !hash)
158285349Sluigi		return -1;
159261909Sluigi
160261909Sluigi	if (sig_len != (key->len * sizeof(u32))) {
161261909Sluigi		printf("Signature is of incorrect length %d\n", sig_len);
162261909Sluigi		return -1;
163261909Sluigi	}
164261909Sluigi
165261909Sluigi	/* Sanity check for stack size */
166261909Sluigi	if (sig_len > ZYNQ_RSA_SPK_SIGNATURE_SIZE) {
167261909Sluigi		printf("Signature length %u exceeds maximum %d\n", sig_len,
168261909Sluigi		       ZYNQ_RSA_SPK_SIGNATURE_SIZE);
169261909Sluigi		return -1;
170261909Sluigi	}
171261909Sluigi
172261909Sluigi	buf = malloc(sig_len);
173261909Sluigi	if (!buf)
174285349Sluigi		return -1;
175285349Sluigi
176285349Sluigi	memcpy(buf, sig, sig_len);
177285349Sluigi
178261909Sluigi	status = zynq_pow_mod((u32 *)key, (u32 *)buf);
179261909Sluigi	if (status == -1) {
180261909Sluigi		free(buf);
181261909Sluigi		return status;
182341477Svmaffione	}
183270063Sluigi
184261909Sluigi	status = zynq_pad_and_check((u8 *)buf, (u8 *)hash);
185341477Svmaffione
186341477Svmaffione	free(buf);
187341477Svmaffione	return status;
188341477Svmaffione}
189341477Svmaffione
190261909Sluigi/*
191341477Svmaffione * Authenticate the partition
192341477Svmaffione */
193341477Svmaffionestatic int zynq_authenticate_part(u8 *buffer, u32 size)
194341477Svmaffione{
195261909Sluigi	u8 hash_signature[32];
196341477Svmaffione	u8 *spk_modular;
197341477Svmaffione	u8 *spk_modular_ex;
198261909Sluigi	u8 *signature_ptr;
199341477Svmaffione	u32 status;
200341477Svmaffione
201341477Svmaffione	debug("%s\n", __func__);
202341477Svmaffione
203341477Svmaffione	signature_ptr = (u8 *)(buffer + size - ZYNQ_RSA_SIGNATURE_SIZE);
204341477Svmaffione
205261909Sluigi	signature_ptr += ZYNQ_RSA_HEADER_SIZE;
206261909Sluigi
207261909Sluigi	signature_ptr += ZYNQ_RSA_MAGIC_WORD_SIZE;
208341477Svmaffione
209341477Svmaffione	ppkmodular = (u8 *)signature_ptr;
210341477Svmaffione	signature_ptr += ZYNQ_RSA_MODULAR_SIZE;
211341477Svmaffione	ppkmodularex = signature_ptr;
212261909Sluigi	signature_ptr += ZYNQ_RSA_MODULAR_EXT_SIZE;
213341477Svmaffione	signature_ptr += ZYNQ_RSA_EXPO_SIZE;
214341477Svmaffione
215341477Svmaffione	sha256_csum_wd((const unsigned char *)signature_ptr,
216341477Svmaffione		       (ZYNQ_RSA_MODULAR_EXT_SIZE + ZYNQ_RSA_EXPO_SIZE +
217341477Svmaffione		       ZYNQ_RSA_MODULAR_SIZE),
218341477Svmaffione		       (unsigned char *)hash_signature, 0x1000);
219261909Sluigi
220341477Svmaffione	spk_modular = (u8 *)signature_ptr;
221261909Sluigi	signature_ptr += ZYNQ_RSA_MODULAR_SIZE;
222341477Svmaffione	spk_modular_ex = (u8 *)signature_ptr;
223341477Svmaffione	signature_ptr += ZYNQ_RSA_MODULAR_EXT_SIZE;
224341477Svmaffione	signature_ptr += ZYNQ_RSA_EXPO_SIZE;
225261909Sluigi
226341477Svmaffione	public_key.len = ZYNQ_RSA_MODULAR_SIZE / sizeof(u32);
227341477Svmaffione	public_key.modulus = (u32 *)ppkmodular;
228341477Svmaffione	public_key.rr = (u32 *)ppkmodularex;
229341477Svmaffione	public_key.n0inv = zynq_calc_inv();
230341477Svmaffione
231261909Sluigi	status = zynq_rsa_verify_key(&public_key, signature_ptr,
232261909Sluigi				     ZYNQ_RSA_SPK_SIGNATURE_SIZE,
233261909Sluigi				     hash_signature);
234261909Sluigi	if (status)
235341477Svmaffione		return status;
236270063Sluigi
237261909Sluigi	signature_ptr += ZYNQ_RSA_SPK_SIGNATURE_SIZE;
238341477Svmaffione
239341477Svmaffione	sha256_csum_wd((const unsigned char *)buffer,
240341477Svmaffione		       (size - ZYNQ_RSA_PARTITION_SIGNATURE_SIZE),
241341477Svmaffione		       (unsigned char *)hash_signature, 0x1000);
242261909Sluigi
243341477Svmaffione	public_key.len = ZYNQ_RSA_MODULAR_SIZE / sizeof(u32);
244341477Svmaffione	public_key.modulus = (u32 *)spk_modular;
245341477Svmaffione	public_key.rr = (u32 *)spk_modular_ex;
246341477Svmaffione	public_key.n0inv = zynq_calc_inv();
247261909Sluigi
248341477Svmaffione	return zynq_rsa_verify_key(&public_key, (u8 *)signature_ptr,
249341477Svmaffione				   ZYNQ_RSA_PARTITION_SIGNATURE_SIZE,
250341477Svmaffione				   (u8 *)hash_signature);
251341477Svmaffione}
252341477Svmaffione
253341477Svmaffione/*
254341477Svmaffione * Parses the partition header and verfies the authenticated and
255341477Svmaffione * encrypted image.
256341477Svmaffione */
257341477Svmaffionestatic int zynq_verify_image(u32 src_ptr)
258261909Sluigi{
259341477Svmaffione	u32 silicon_ver, image_base_addr, status;
260341477Svmaffione	u32 partition_num = 0;
261341477Svmaffione	u32 efuseval, srcaddr, size, fsbl_len;
262341477Svmaffione	struct partition_hdr *hdr_ptr;
263341477Svmaffione	u32 part_data_len, part_img_len, part_attr;
264341477Svmaffione	u32 part_load_addr, part_dst_addr, part_chksum_offset;
265341477Svmaffione	u32 part_start_addr, part_total_size, partitioncount;
266341477Svmaffione	bool encrypt_part_flag = false;
267341477Svmaffione	bool part_chksum_flag = false;
268341477Svmaffione	bool signed_part_flag = false;
269341477Svmaffione
270341477Svmaffione	image_base_addr = src_ptr;
271341477Svmaffione
272341477Svmaffione	silicon_ver = zynq_get_silicon_version();
273341477Svmaffione
274341477Svmaffione	/* RSA not supported in silicon versions 1.0 and 2.0 */
275341477Svmaffione	if (silicon_ver == 0 || silicon_ver == 1)
276341477Svmaffione		return -1;
277341477Svmaffione
278341477Svmaffione	zynq_get_partition_info(image_base_addr, &fsbl_len,
279341477Svmaffione				&part_hdr[0]);
280341477Svmaffione
281341477Svmaffione	/* Extract ppk if efuse was blown Otherwise return error */
282261909Sluigi	efuseval = readl(&efuse_base->status);
283261909Sluigi	if (!(efuseval & ZYNQ_EFUSE_RSA_ENABLE_MASK))
284261909Sluigi		return -1;
285261909Sluigi
286261909Sluigi	zynq_extract_ppk(fsbl_len);
287261909Sluigi
288261909Sluigi	partitioncount = zynq_get_part_count(&part_hdr[0]);
289261909Sluigi
290261909Sluigi	/*
291261909Sluigi	 * As the first two partitions are related to fsbl,
292261909Sluigi	 * we can ignore those two in bootimage and the below
293261909Sluigi	 * code doesn't need to validate it as fsbl is already
294261909Sluigi	 * done by now
295261909Sluigi	 */
296261909Sluigi	if (partitioncount <= 2 ||
297261909Sluigi	    partitioncount > ZYNQ_MAX_PARTITION_NUMBER)
298261909Sluigi		return -1;
299261909Sluigi
300261909Sluigi	while (partition_num < partitioncount) {
301261909Sluigi		if (((part_hdr[partition_num].partitionattr &
302261909Sluigi		   ZYNQ_ATTRIBUTE_RSA_PART_OWNER_MASK) >> 16) !=
303261909Sluigi		   ZYNQ_RSA_PART_OWNER_UBOOT) {
304261909Sluigi			printf("UBOOT is not Owner for partition %d\n",
305261909Sluigi			       partition_num);
306261909Sluigi			partition_num++;
307261909Sluigi			continue;
308261909Sluigi		}
309261909Sluigi		hdr_ptr = &part_hdr[partition_num];
310261909Sluigi		status = zynq_validate_hdr(hdr_ptr);
311261909Sluigi		if (status)
312261909Sluigi			return status;
313341477Svmaffione
314261909Sluigi		part_data_len = hdr_ptr->datawordlen;
315261909Sluigi		part_img_len = hdr_ptr->imagewordlen;
316261909Sluigi		part_attr = hdr_ptr->partitionattr;
317261909Sluigi		part_load_addr = hdr_ptr->loadaddr;
318261909Sluigi		part_chksum_offset = hdr_ptr->checksumoffset;
319261909Sluigi		part_start_addr = hdr_ptr->partitionstart;
320261909Sluigi		part_total_size = hdr_ptr->partitionwordlen;
321261909Sluigi
322261909Sluigi		if (part_data_len != part_img_len) {
323261909Sluigi			debug("Encrypted\n");
324261909Sluigi			encrypt_part_flag = true;
325261909Sluigi		}
326261909Sluigi
327261909Sluigi		if (part_attr & ZYNQ_ATTRIBUTE_CHECKSUM_TYPE_MASK)
328261909Sluigi			part_chksum_flag = true;
329341477Svmaffione
330261909Sluigi		if (part_attr & ZYNQ_ATTRIBUTE_RSA_PRESENT_MASK) {
331261909Sluigi			debug("RSA Signed\n");
332261909Sluigi			signed_part_flag = true;
333261909Sluigi			size = part_total_size << WORD_LENGTH_SHIFT;
334261909Sluigi		} else {
335261909Sluigi			size = part_img_len;
336261909Sluigi		}
337261909Sluigi
338285349Sluigi		if (!signed_part_flag && !part_chksum_flag) {
339285349Sluigi			printf("Partition not signed & no chksum\n");
340261909Sluigi			partition_num++;
341261909Sluigi			continue;
342261909Sluigi		}
343261909Sluigi
344341477Svmaffione		srcaddr = image_base_addr +
345261909Sluigi			  (part_start_addr << WORD_LENGTH_SHIFT);
346261909Sluigi
347261909Sluigi		/*
348261909Sluigi		 * This validation is just for PS DDR.
349341477Svmaffione		 * TODO: Update this for PL DDR check as well.
350341477Svmaffione		 */
351261909Sluigi		if (part_load_addr < gd->bd->bi_dram[0].start &&
352261909Sluigi		    ((part_load_addr + part_data_len) >
353261909Sluigi		    (gd->bd->bi_dram[0].start +
354341477Svmaffione		     gd->bd->bi_dram[0].size))) {
355285349Sluigi			printf("INVALID_LOAD_ADDRESS_FAIL\n");
356341477Svmaffione			return -1;
357285349Sluigi		}
358341477Svmaffione
359341477Svmaffione		if (part_attr & ZYNQ_ATTRIBUTE_PL_IMAGE_MASK)
360341477Svmaffione			part_load_addr = srcaddr;
361341477Svmaffione		else
362341477Svmaffione			memcpy((u32 *)part_load_addr, (u32 *)srcaddr,
363341477Svmaffione			       size);
364341477Svmaffione
365341477Svmaffione		if (part_chksum_flag) {
366341477Svmaffione			part_chksum_offset = image_base_addr +
367285349Sluigi					     (part_chksum_offset <<
368261909Sluigi					     WORD_LENGTH_SHIFT);
369341477Svmaffione			status = zynq_validate_partition(part_load_addr,
370261909Sluigi							 (part_total_size <<
371261909Sluigi							  WORD_LENGTH_SHIFT),
372261909Sluigi							 part_chksum_offset);
373261909Sluigi			if (status != 0) {
374261909Sluigi				printf("PART_CHKSUM_FAIL\n");
375261909Sluigi				return -1;
376261909Sluigi			}
377261909Sluigi			debug("Partition Validation Done\n");
378261909Sluigi		}
379261909Sluigi
380261909Sluigi		if (signed_part_flag) {
381261909Sluigi			status = zynq_authenticate_part((u8 *)part_load_addr,
382267128Sluigi							size);
383261909Sluigi			if (status != 0) {
384261909Sluigi				printf("AUTHENTICATION_FAIL\n");
385261909Sluigi				return -1;
386261909Sluigi			}
387341477Svmaffione			debug("Authentication Done\n");
388341477Svmaffione		}
389261909Sluigi
390261909Sluigi		if (encrypt_part_flag) {
391261909Sluigi			debug("DECRYPTION\n");
392261909Sluigi
393261909Sluigi			part_dst_addr = part_load_addr;
394261909Sluigi
395267128Sluigi			if (part_attr & ZYNQ_ATTRIBUTE_PL_IMAGE_MASK) {
396261909Sluigi				partition_num++;
397261909Sluigi				continue;
398261909Sluigi			}
399261909Sluigi
400261909Sluigi			status = zynq_decrypt_load(part_load_addr,
401261909Sluigi						   part_img_len,
402261909Sluigi						   part_dst_addr,
403261909Sluigi						   part_data_len,
404261909Sluigi						   BIT_NONE);
405261909Sluigi			if (status != 0) {
406261909Sluigi				printf("DECRYPTION_FAIL\n");
407261909Sluigi				return -1;
408261909Sluigi			}
409261909Sluigi		}
410341477Svmaffione		partition_num++;
411261909Sluigi	}
412261909Sluigi
413261909Sluigi	return 0;
414261909Sluigi}
415261909Sluigi
416261909Sluigistatic int do_zynq_rsa(struct cmd_tbl *cmdtp, int flag, int argc,
417341477Svmaffione		       char *const argv[])
418341477Svmaffione{
419285349Sluigi	u32 src_ptr;
420285349Sluigi	char *endp;
421261909Sluigi
422261909Sluigi	if (argc != cmdtp->maxargs)
423341477Svmaffione		return CMD_RET_FAILURE;
424341477Svmaffione
425341477Svmaffione	src_ptr = hextoul(argv[2], &endp);
426341477Svmaffione	if (*argv[2] == 0 || *endp != 0)
427341477Svmaffione		return CMD_RET_USAGE;
428341477Svmaffione
429341477Svmaffione	if (zynq_verify_image(src_ptr))
430341477Svmaffione		return CMD_RET_FAILURE;
431341477Svmaffione
432341477Svmaffione	return CMD_RET_SUCCESS;
433341477Svmaffione}
434341477Svmaffione#endif
435341477Svmaffione
436341477Svmaffione#ifdef CONFIG_CMD_ZYNQ_AES
437341477Svmaffionestatic int zynq_decrypt_image(struct cmd_tbl *cmdtp, int flag, int argc,
438341477Svmaffione			      char *const argv[])
439341477Svmaffione{
440341477Svmaffione	char *endp;
441341477Svmaffione	u32 srcaddr, srclen, dstaddr, dstlen;
442341477Svmaffione	int status;
443341477Svmaffione	u8 imgtype = BIT_NONE;
444342033Svmaffione
445341477Svmaffione	if (argc < 5 && argc > cmdtp->maxargs)
446341477Svmaffione		return CMD_RET_USAGE;
447341477Svmaffione
448341477Svmaffione	if (argc == 5) {
449341477Svmaffione		if (!strcmp("load", argv[2]))
450341477Svmaffione			imgtype = BIT_FULL;
451341477Svmaffione		else if (!strcmp("loadp", argv[2]))
452341477Svmaffione			imgtype = BIT_PARTIAL;
453341477Svmaffione		else
454341477Svmaffione			return CMD_RET_USAGE;
455341477Svmaffione
456341477Svmaffione		srcaddr = hextoul(argv[3], &endp);
457341477Svmaffione		if (*argv[3] == 0 || *endp != 0)
458341477Svmaffione			return CMD_RET_USAGE;
459341477Svmaffione		srclen = hextoul(argv[4], &endp);
460341477Svmaffione		if (*argv[4] == 0 || *endp != 0)
461341477Svmaffione			return CMD_RET_USAGE;
462341477Svmaffione
463341477Svmaffione		dstaddr = 0xFFFFFFFF;
464341477Svmaffione		dstlen = srclen;
465341477Svmaffione	} else {
466341477Svmaffione		srcaddr = hextoul(argv[2], &endp);
467341477Svmaffione		if (*argv[2] == 0 || *endp != 0)
468341477Svmaffione			return CMD_RET_USAGE;
469341477Svmaffione		srclen = hextoul(argv[3], &endp);
470341477Svmaffione		if (*argv[3] == 0 || *endp != 0)
471341477Svmaffione			return CMD_RET_USAGE;
472341477Svmaffione		dstaddr = hextoul(argv[4], &endp);
473341477Svmaffione		if (*argv[4] == 0 || *endp != 0)
474341477Svmaffione			return CMD_RET_USAGE;
475341477Svmaffione		dstlen = hextoul(argv[5], &endp);
476341477Svmaffione		if (*argv[5] == 0 || *endp != 0)
477341477Svmaffione			return CMD_RET_USAGE;
478341477Svmaffione	}
479341477Svmaffione
480341477Svmaffione	/*
481341477Svmaffione	 * Roundup source and destination lengths to
482341477Svmaffione	 * word size
483341477Svmaffione	 */
484341477Svmaffione	if (srclen % 4)
485341477Svmaffione		srclen = roundup(srclen, 4);
486341477Svmaffione	if (dstlen % 4)
487261909Sluigi		dstlen = roundup(dstlen, 4);
488341477Svmaffione
489341477Svmaffione	status = zynq_decrypt_load(srcaddr, srclen >> 2, dstaddr,
490341477Svmaffione				   dstlen >> 2, imgtype);
491342033Svmaffione	if (status != 0)
492341477Svmaffione		return CMD_RET_FAILURE;
493341477Svmaffione
494341477Svmaffione	return CMD_RET_SUCCESS;
495341477Svmaffione}
496341477Svmaffione#endif
497341477Svmaffione
498341477Svmaffionestatic struct cmd_tbl zynq_commands[] = {
499261909Sluigi#ifdef CONFIG_CMD_ZYNQ_RSA
500341477Svmaffione	U_BOOT_CMD_MKENT(rsa, 3, 1, do_zynq_rsa, "", ""),
501341477Svmaffione#endif
502341477Svmaffione#ifdef CONFIG_CMD_ZYNQ_AES
503341477Svmaffione	U_BOOT_CMD_MKENT(aes, 6, 1, zynq_decrypt_image, "", ""),
504341477Svmaffione#endif
505341477Svmaffione};
506261909Sluigi
507261909Sluigistatic int do_zynq(struct cmd_tbl *cmdtp, int flag, int argc,
508261909Sluigi		   char *const argv[])
509261909Sluigi{
510261909Sluigi	struct cmd_tbl *zynq_cmd;
511261909Sluigi	int ret;
512261909Sluigi
513261909Sluigi	if (!ARRAY_SIZE(zynq_commands)) {
514261909Sluigi		puts("No zynq specific command enabled\n");
515261909Sluigi		return CMD_RET_USAGE;
516261909Sluigi	}
517261909Sluigi
518261909Sluigi	if (argc < 2)
519341477Svmaffione		return CMD_RET_USAGE;
520261909Sluigi	zynq_cmd = find_cmd_tbl(argv[1], zynq_commands,
521261909Sluigi				ARRAY_SIZE(zynq_commands));
522261909Sluigi	if (!zynq_cmd)
523261909Sluigi		return CMD_RET_USAGE;
524261909Sluigi
525261909Sluigi	ret = zynq_cmd->cmd(zynq_cmd, flag, argc, argv);
526261909Sluigi
527261909Sluigi	return cmd_process_error(zynq_cmd, ret);
528267128Sluigi}
529261909Sluigi
530267128SluigiU_BOOT_LONGHELP(zynq,
531261909Sluigi	""
532261909Sluigi#ifdef CONFIG_CMD_ZYNQ_RSA
533261909Sluigi	"rsa <baseaddr>  - Verifies the authenticated and encrypted\n"
534261909Sluigi	"                  zynq images and loads them back to load\n"
535267128Sluigi	"                  addresses as specified in BOOT image(BOOT.BIN)\n"
536261909Sluigi#endif
537261909Sluigi#ifdef CONFIG_CMD_ZYNQ_AES
538261909Sluigi	"aes <srcaddr> <srclen> <dstaddr> <dstlen>\n"
539261909Sluigi	"                - Decrypts the encrypted image present in source\n"
540341477Svmaffione	"                  address and places the decrypted image at\n"
541261909Sluigi	"                  destination address\n"
542261909Sluigi	"aes load <srcaddr> <srclen>\n"
543261909Sluigi	"aes loadp <srcaddr> <srclen>\n"
544261909Sluigi	"       if operation type is load or loadp, it loads the encrypted\n"
545261909Sluigi	"       full or partial bitstream on to PL respectively.\n"
546261909Sluigi#endif
547341477Svmaffione	);
548341477Svmaffione
549261909SluigiU_BOOT_CMD(zynq,	6,	0,	do_zynq,
550261909Sluigi	   "Zynq specific commands", zynq_help_text
551261909Sluigi);
552261909Sluigi