1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) Copyright 2018 Xilinx, Inc.
4 * Siva Durga Prasad Paladugu <siva.durga.prasad.paladugu@amd.com>>
5 */
6
7#include <common.h>
8#include <command.h>
9#include <cpu_func.h>
10#include <env.h>
11#include <malloc.h>
12#include <memalign.h>
13#include <zynqmp_firmware.h>
14#include <asm/arch/hardware.h>
15#include <asm/arch/sys_proto.h>
16#include <asm/io.h>
17#include <mach/zynqmp_aes.h>
18
19static int do_zynqmp_verify_secure(struct cmd_tbl *cmdtp, int flag, int argc,
20				   char *const argv[])
21{
22	u64 src_addr, addr;
23	u32 len, src_lo, src_hi;
24	u8 *key_ptr = NULL;
25	int ret;
26	u32 key_lo = 0;
27	u32 key_hi = 0;
28	u32 ret_payload[PAYLOAD_ARG_CNT];
29
30	if (argc < 4)
31		return CMD_RET_USAGE;
32
33	src_addr = simple_strtoull(argv[2], NULL, 16);
34	len = hextoul(argv[3], NULL);
35
36	if (argc == 5)
37		key_ptr = (uint8_t *)(uintptr_t)simple_strtoull(argv[4],
38								NULL, 16);
39
40	if ((ulong)src_addr != ALIGN((ulong)src_addr,
41				     CONFIG_SYS_CACHELINE_SIZE)) {
42		printf("Failed: source address not aligned:%lx\n",
43		       (ulong)src_addr);
44		return -EINVAL;
45	}
46
47	src_lo = lower_32_bits((ulong)src_addr);
48	src_hi = upper_32_bits((ulong)src_addr);
49	flush_dcache_range((ulong)src_addr, (ulong)(src_addr + len));
50
51	if (key_ptr) {
52		key_lo = lower_32_bits((ulong)key_ptr);
53		key_hi = upper_32_bits((ulong)key_ptr);
54		flush_dcache_range((ulong)key_ptr,
55				   (ulong)(key_ptr + KEY_PTR_LEN));
56	}
57
58	ret = xilinx_pm_request(PM_SECURE_IMAGE, src_lo, src_hi,
59				key_lo, key_hi, ret_payload);
60	if (ret) {
61		printf("Failed: secure op status:0x%x\n", ret);
62	} else {
63		addr = (u64)ret_payload[1] << 32 | ret_payload[2];
64		printf("Verified image at 0x%llx\n", addr);
65		env_set_hex("zynqmp_verified_img_addr", addr);
66	}
67
68	return ret;
69}
70
71static int do_zynqmp_mmio_read(struct cmd_tbl *cmdtp, int flag, int argc,
72			       char *const argv[])
73{
74	u32 read_val, addr;
75	int ret;
76
77	if (argc != cmdtp->maxargs)
78		return CMD_RET_USAGE;
79
80	addr = hextoul(argv[2], NULL);
81
82	ret = zynqmp_mmio_read(addr, &read_val);
83	if (!ret)
84		printf("mmio read value at 0x%x = 0x%x\n",
85		       addr, read_val);
86	else
87		printf("Failed: mmio read\n");
88
89	return ret;
90}
91
92static int do_zynqmp_mmio_write(struct cmd_tbl *cmdtp, int flag, int argc,
93				char *const argv[])
94{
95	u32 addr, mask, val;
96	int ret;
97
98	if (argc != cmdtp->maxargs)
99		return CMD_RET_USAGE;
100
101	addr = hextoul(argv[2], NULL);
102	mask = hextoul(argv[3], NULL);
103	val = hextoul(argv[4], NULL);
104
105	ret = zynqmp_mmio_write(addr, mask, val);
106	if (ret != 0)
107		printf("Failed: mmio write\n");
108
109	return ret;
110}
111
112static int do_zynqmp_aes(struct cmd_tbl *cmdtp, int flag, int argc,
113			 char * const argv[])
114{
115	ALLOC_CACHE_ALIGN_BUFFER(struct zynqmp_aes, aes, 1);
116
117	if (zynqmp_firmware_version() <= PMUFW_V1_0) {
118		puts("ERR: PMUFW v1.0 or less is detected\n");
119		puts("ERR: Encrypt/Decrypt feature is not supported\n");
120		puts("ERR: Please upgrade PMUFW\n");
121		return CMD_RET_FAILURE;
122	}
123
124	if (argc < cmdtp->maxargs - 1)
125		return CMD_RET_USAGE;
126
127	aes->srcaddr = hextoul(argv[2], NULL);
128	aes->ivaddr = hextoul(argv[3], NULL);
129	aes->len = hextoul(argv[4], NULL);
130	aes->op = hextoul(argv[5], NULL);
131	aes->keysrc = hextoul(argv[6], NULL);
132	aes->dstaddr = hextoul(argv[7], NULL);
133
134	if (aes->keysrc == 0) {
135		if (argc < cmdtp->maxargs)
136			return CMD_RET_USAGE;
137
138		aes->keyaddr = hextoul(argv[8], NULL);
139	}
140
141	return zynqmp_aes_operation(aes);
142}
143
144#ifdef CONFIG_DEFINE_TCM_OCM_MMAP
145static int do_zynqmp_tcm_init(struct cmd_tbl *cmdtp, int flag, int argc,
146			      char *const argv[])
147{
148	u8 mode;
149
150	if (argc != cmdtp->maxargs)
151		return CMD_RET_USAGE;
152
153	if (strcmp(argv[2], "lockstep") && strcmp(argv[2], "split")) {
154		printf("mode param should be lockstep or split\n");
155		return CMD_RET_FAILURE;
156	}
157
158	mode = hextoul(argv[2], NULL);
159	if (mode != TCM_LOCK && mode != TCM_SPLIT) {
160		printf("Mode should be either 0(lock)/1(split)\n");
161		return CMD_RET_FAILURE;
162	}
163
164	dcache_disable();
165	tcm_init(mode);
166	dcache_enable();
167
168	return CMD_RET_SUCCESS;
169}
170#endif
171
172static int do_zynqmp_pmufw(struct cmd_tbl *cmdtp, int flag, int argc,
173			   char * const argv[])
174{
175	u32 addr, size;
176
177	if (argc != cmdtp->maxargs)
178		return CMD_RET_USAGE;
179
180	if (!strncmp(argv[2], "node", 4)) {
181		u32 id;
182		int ret;
183
184		if (!strncmp(argv[3], "close", 5))
185			return zynqmp_pmufw_config_close();
186
187		id = dectoul(argv[3], NULL);
188		if (!id) {
189			printf("Incorrect ID passed\n");
190			return CMD_RET_USAGE;
191		}
192
193		printf("Enable permission for node ID %d\n", id);
194
195		ret = zynqmp_pmufw_node(id);
196		if (ret == -ENODEV)
197			ret = 0;
198
199		return ret;
200	}
201
202	addr = hextoul(argv[2], NULL);
203	size = hextoul(argv[3], NULL);
204
205	zynqmp_pmufw_load_config_object((const void *)(uintptr_t)addr,
206					(size_t)size);
207
208	return 0;
209}
210
211static int do_zynqmp_rsa(struct cmd_tbl *cmdtp, int flag, int argc,
212			 char * const argv[])
213{
214	u64 srcaddr, mod, exp;
215	u32 srclen, rsaop, size, ret_payload[PAYLOAD_ARG_CNT];
216	int ret;
217
218	if (argc != cmdtp->maxargs)
219		return CMD_RET_USAGE;
220
221	if (zynqmp_firmware_version() <= PMUFW_V1_0) {
222		puts("ERR: PMUFW v1.0 or less is detected\n");
223		puts("ERR: Encrypt/Decrypt feature is not supported\n");
224		puts("ERR: Please upgrade PMUFW\n");
225		return CMD_RET_FAILURE;
226	}
227
228	srcaddr = hextoul(argv[2], NULL);
229	srclen = hextoul(argv[3], NULL);
230	if (srclen != RSA_KEY_SIZE) {
231		puts("ERR: srclen should be equal to 0x200(512 bytes)\n");
232		return CMD_RET_USAGE;
233	}
234
235	mod = hextoul(argv[4], NULL);
236	exp = hextoul(argv[5], NULL);
237	rsaop = hextoul(argv[6], NULL);
238	if (!(rsaop == 0 || rsaop == 1)) {
239		puts("ERR: rsaop should be either 0 or 1\n");
240		return CMD_RET_USAGE;
241	}
242
243	memcpy((void *)srcaddr + srclen, (void *)mod, MODULUS_LEN);
244
245	/*
246	 * For encryption we load public exponent (key size 4096-bits),
247	 * for decryption we load private exponent (32-bits)
248	 */
249	if (rsaop) {
250		memcpy((void *)srcaddr + srclen + MODULUS_LEN,
251		       (void *)exp, PUB_EXPO_LEN);
252		size = srclen + MODULUS_LEN + PUB_EXPO_LEN;
253	} else {
254		memcpy((void *)srcaddr + srclen + MODULUS_LEN,
255		       (void *)exp, PRIV_EXPO_LEN);
256		size = srclen + MODULUS_LEN + PRIV_EXPO_LEN;
257	}
258
259	flush_dcache_range((ulong)srcaddr,
260			   (ulong)(srcaddr) + roundup(size, ARCH_DMA_MINALIGN));
261
262	ret = xilinx_pm_request(PM_SECURE_RSA, upper_32_bits((ulong)srcaddr),
263				lower_32_bits((ulong)srcaddr), srclen, rsaop,
264				ret_payload);
265	if (ret || ret_payload[1]) {
266		printf("Failed: RSA status:0x%x, errcode:0x%x\n",
267		       ret, ret_payload[1]);
268		return CMD_RET_FAILURE;
269	}
270
271	return CMD_RET_SUCCESS;
272}
273
274static int do_zynqmp_sha3(struct cmd_tbl *cmdtp, int flag,
275			  int argc, char * const argv[])
276{
277	u64 srcaddr, hashaddr;
278	u32 srclen, ret_payload[PAYLOAD_ARG_CNT];
279	int ret;
280
281	if (argc > cmdtp->maxargs || argc < (cmdtp->maxargs - 1))
282		return CMD_RET_USAGE;
283
284	if (zynqmp_firmware_version() <= PMUFW_V1_0) {
285		puts("ERR: PMUFW v1.0 or less is detected\n");
286		puts("ERR: Encrypt/Decrypt feature is not supported\n");
287		puts("ERR: Please upgrade PMUFW\n");
288		return CMD_RET_FAILURE;
289	}
290
291	srcaddr = hextoul(argv[2], NULL);
292	srclen = hextoul(argv[3], NULL);
293
294	if (argc == 5) {
295		hashaddr = hextoul(argv[4], NULL);
296		flush_dcache_range(hashaddr,
297				   hashaddr + roundup(ZYNQMP_SHA3_SIZE,
298						      ARCH_DMA_MINALIGN));
299	} else {
300		hashaddr = srcaddr;
301	}
302
303	/* Check srcaddr or srclen != 0 */
304	if (!srcaddr || !srclen) {
305		puts("ERR: srcaddr & srclen should not be 0\n");
306		return CMD_RET_USAGE;
307	}
308
309	flush_dcache_range(srcaddr,
310			   srcaddr + roundup(srclen, ARCH_DMA_MINALIGN));
311
312	ret = xilinx_pm_request(PM_SECURE_SHA, 0, 0, 0,
313				ZYNQMP_SHA3_INIT, ret_payload);
314	if (ret || ret_payload[1]) {
315		printf("Failed: SHA INIT status:0x%x, errcode:0x%x\n",
316		       ret, ret_payload[1]);
317		return CMD_RET_FAILURE;
318	}
319
320	ret = xilinx_pm_request(PM_SECURE_SHA, upper_32_bits((ulong)srcaddr),
321				lower_32_bits((ulong)srcaddr),
322				srclen, ZYNQMP_SHA3_UPDATE, ret_payload);
323	if (ret || ret_payload[1]) {
324		printf("Failed: SHA UPDATE status:0x%x, errcode:0x%x\n",
325		       ret, ret_payload[1]);
326		return CMD_RET_FAILURE;
327	}
328
329	ret = xilinx_pm_request(PM_SECURE_SHA, upper_32_bits((ulong)hashaddr),
330				lower_32_bits((ulong)hashaddr),
331				ZYNQMP_SHA3_SIZE, ZYNQMP_SHA3_FINAL,
332				ret_payload);
333	if (ret || ret_payload[1]) {
334		printf("Failed: SHA FINAL status:0x%x, errcode:0x%x\n",
335		       ret, ret_payload[1]);
336		return CMD_RET_FAILURE;
337	}
338
339	return CMD_RET_SUCCESS;
340}
341
342static struct cmd_tbl cmd_zynqmp_sub[] = {
343	U_BOOT_CMD_MKENT(secure, 5, 0, do_zynqmp_verify_secure, "", ""),
344	U_BOOT_CMD_MKENT(pmufw, 4, 0, do_zynqmp_pmufw, "", ""),
345	U_BOOT_CMD_MKENT(mmio_read, 3, 0, do_zynqmp_mmio_read, "", ""),
346	U_BOOT_CMD_MKENT(mmio_write, 5, 0, do_zynqmp_mmio_write, "", ""),
347	U_BOOT_CMD_MKENT(aes, 9, 0, do_zynqmp_aes, "", ""),
348	U_BOOT_CMD_MKENT(rsa, 7, 0, do_zynqmp_rsa, "", ""),
349	U_BOOT_CMD_MKENT(sha3, 5, 0, do_zynqmp_sha3, "", ""),
350#ifdef CONFIG_DEFINE_TCM_OCM_MMAP
351	U_BOOT_CMD_MKENT(tcminit, 3, 0, do_zynqmp_tcm_init, "", ""),
352#endif
353};
354
355/**
356 * do_zynqmp - Handle the "zynqmp" command-line command
357 * @cmdtp:	Command data struct pointer
358 * @flag:	Command flag
359 * @argc:	Command-line argument count
360 * @argv:	Array of command-line arguments
361 *
362 * Processes the zynqmp specific commands
363 *
364 * Return: return 0 on success and CMD_RET_USAGE incase of misuse and error
365 */
366static int do_zynqmp(struct cmd_tbl *cmdtp, int flag, int argc,
367		     char *const argv[])
368{
369	struct cmd_tbl *c;
370	int ret = CMD_RET_USAGE;
371
372	if (argc < 2)
373		return CMD_RET_USAGE;
374
375	c = find_cmd_tbl(argv[1], &cmd_zynqmp_sub[0],
376			 ARRAY_SIZE(cmd_zynqmp_sub));
377	if (c)
378		ret = c->cmd(c, flag, argc, argv);
379
380	return cmd_process_error(c, ret);
381}
382
383/***************************************************/
384U_BOOT_LONGHELP(zynqmp,
385	"secure src len [key_addr] - verifies secure images of $len bytes\n"
386	"                            long at address $src. Optional key_addr\n"
387	"                            can be specified if user key needs to\n"
388	"                            be used for decryption\n"
389	"zynqmp mmio_read address - read from address\n"
390	"zynqmp mmio_write address mask value - write value after masking to\n"
391	"					address\n"
392	"zynqmp aes srcaddr ivaddr len aesop keysrc dstaddr [keyaddr] -\n"
393	"	Encrypts or decrypts blob of data at src address and puts it\n"
394	"	back to dstaddr using key and iv at keyaddr and ivaddr\n"
395	"	respectively. keysrc value specifies from which source key\n"
396	"	has to be used, it can be User/Device/PUF key. A value of 0\n"
397	"	for KUP(user key),1 for DeviceKey and 2 for PUF key. The\n"
398	"	aesop value specifies the operation which can be 0 for\n"
399	"	decrypt and 1 for encrypt operation\n"
400#ifdef CONFIG_DEFINE_TCM_OCM_MMAP
401	"zynqmp tcminit mode - Initialize the TCM with zeros. TCM needs to be\n"
402	"		       initialized before accessing to avoid ECC\n"
403	"		       errors. mode specifies in which mode TCM has\n"
404	"		       to be initialized. Supported modes will be\n"
405	"		       lock(0)/split(1)\n"
406#endif
407	"zynqmp pmufw address size - load PMU FW configuration object\n"
408	"zynqmp pmufw node <id> - load PMU FW configuration object, <id> in dec\n"
409	"zynqmp pmufw node close - disable config object loading\n"
410	"	node: keyword, id: NODE_ID in decimal format\n"
411	"zynqmp rsa srcaddr srclen mod exp rsaop -\n"
412	"	Performs RSA encryption and RSA decryption on blob of data\n"
413	"	at srcaddr and puts it back in srcaddr using modulus and\n"
414	"	public or private exponent\n"
415	"	srclen : must be key size(4096 bits)\n"
416	"	exp :	private key exponent for RSA decryption(4096 bits)\n"
417	"		public key exponent for RSA encryption(32 bits)\n"
418	"	rsaop :	0 for RSA Decryption, 1 for RSA Encryption\n"
419	"zynqmp sha3 srcaddr srclen [key_addr] -\n"
420	"	Generates sha3 hash value for data blob at srcaddr and puts\n"
421	"	48 bytes hash value into srcaddr\n"
422	"	Optional key_addr can be specified for saving sha3 hash value\n"
423	"	Note: srcaddr/srclen should not be 0\n"
424	);
425
426U_BOOT_CMD(
427	zynqmp, 9, 1, do_zynqmp,
428	"ZynqMP sub-system",
429	zynqmp_help_text
430);
431