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