1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2018-2019, 2022 NXP 4 */ 5 6#include <common.h> 7#include <command.h> 8#include <errno.h> 9#include <imx_container.h> 10#include <log.h> 11#include <asm/global_data.h> 12#include <asm/io.h> 13#include <firmware/imx/sci/sci.h> 14#include <asm/mach-imx/sys_proto.h> 15#include <asm/arch-imx/cpu.h> 16#include <asm/arch/sys_proto.h> 17#include <console.h> 18#include <cpu_func.h> 19#include "u-boot/sha256.h" 20#include <asm/mach-imx/ahab.h> 21 22DECLARE_GLOBAL_DATA_PTR; 23 24#define SEC_SECURE_RAM_BASE (0x31800000UL) 25#define SEC_SECURE_RAM_END_BASE (SEC_SECURE_RAM_BASE + 0xFFFFUL) 26#define SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE (0x60000000UL) 27 28#define SECO_PT 2U 29#define AHAB_HASH_TYPE_MASK 0x00000700 30#define AHAB_HASH_TYPE_SHA256 0 31 32int ahab_auth_cntr_hdr(struct container_hdr *container, u16 length) 33{ 34 int err; 35 36 memcpy((void *)SEC_SECURE_RAM_BASE, (const void *)container, 37 ALIGN(length, CONFIG_SYS_CACHELINE_SIZE)); 38 39 err = sc_seco_authenticate(-1, SC_SECO_AUTH_CONTAINER, 40 SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE); 41 if (err) 42 printf("Authenticate container hdr failed, return %d\n", err); 43 44 return err; 45} 46 47int ahab_auth_release(void) 48{ 49 int err; 50 51 err = sc_seco_authenticate(-1, SC_SECO_REL_CONTAINER, 0); 52 if (err) 53 printf("Error: release container failed!\n"); 54 55 return err; 56} 57 58int ahab_verify_cntr_image(struct boot_img_t *img, int image_index) 59{ 60 sc_faddr_t start, end; 61 sc_rm_mr_t mr; 62 int err; 63 int ret = 0; 64 65 debug("img %d, dst 0x%llx, src 0x%x, size 0x%x\n", 66 image_index, img->dst, img->offset, img->size); 67 68 /* Find the memreg and set permission for seco pt */ 69 err = sc_rm_find_memreg(-1, &mr, 70 img->dst & ~(CONFIG_SYS_CACHELINE_SIZE - 1), 71 ALIGN(img->dst + img->size, CONFIG_SYS_CACHELINE_SIZE) - 1); 72 73 if (err) { 74 printf("Error: can't find memreg for image load address 0x%llx, error %d\n", 75 img->dst, err); 76 return -ENOMEM; 77 } 78 79 err = sc_rm_get_memreg_info(-1, mr, &start, &end); 80 if (!err) 81 debug("memreg %u 0x%llx -- 0x%llx\n", mr, start, end); 82 83 err = sc_rm_set_memreg_permissions(-1, mr, 84 SECO_PT, SC_RM_PERM_FULL); 85 if (err) { 86 printf("Set permission failed for img %d, error %d\n", 87 image_index, err); 88 return -EPERM; 89 } 90 91 err = sc_seco_authenticate(-1, SC_SECO_VERIFY_IMAGE, 92 1 << image_index); 93 if (err) { 94 printf("Authenticate img %d failed, return %d\n", 95 image_index, err); 96 ret = -EIO; 97 } 98 99 err = sc_rm_set_memreg_permissions(-1, mr, 100 SECO_PT, SC_RM_PERM_NONE); 101 if (err) { 102 printf("Remove permission failed for img %d, error %d\n", 103 image_index, err); 104 ret = -EPERM; 105 } 106 107 return ret; 108} 109 110static inline bool check_in_dram(ulong addr) 111{ 112 int i; 113 struct bd_info *bd = gd->bd; 114 115 for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) { 116 if (bd->bi_dram[i].size) { 117 if (addr >= bd->bi_dram[i].start && 118 addr < (bd->bi_dram[i].start + bd->bi_dram[i].size)) 119 return true; 120 } 121 } 122 123 return false; 124} 125 126int authenticate_os_container(ulong addr) 127{ 128 struct container_hdr *phdr; 129 int i, ret = 0; 130 int err; 131 u16 length; 132 struct boot_img_t *img; 133 unsigned long s, e; 134#ifdef CONFIG_ARMV8_CE_SHA256 135 u8 hash_value[SHA256_SUM_LEN]; 136#endif 137 138 if (addr % 4) { 139 puts("Error: Image's address is not 4 byte aligned\n"); 140 return -EINVAL; 141 } 142 143 if (!check_in_dram(addr)) { 144 puts("Error: Image's address is invalid\n"); 145 return -EINVAL; 146 } 147 148 phdr = (struct container_hdr *)addr; 149 if (!valid_container_hdr(phdr)) { 150 printf("Error: Wrong container header\n"); 151 return -EFAULT; 152 } 153 154 if (!phdr->num_images) { 155 printf("Error: Wrong container, no image found\n"); 156 return -EFAULT; 157 } 158 159 length = phdr->length_lsb + (phdr->length_msb << 8); 160 161 debug("container length %u\n", length); 162 163 err = ahab_auth_cntr_hdr(phdr, length); 164 if (err) { 165 ret = -EIO; 166 goto exit; 167 } 168 169 /* Copy images to dest address */ 170 for (i = 0; i < phdr->num_images; i++) { 171 img = (struct boot_img_t *)(addr + 172 sizeof(struct container_hdr) + 173 i * sizeof(struct boot_img_t)); 174 175 debug("img %d, dst 0x%x, src 0x%lux, size 0x%x\n", 176 i, (uint32_t) img->dst, img->offset + addr, img->size); 177 178 memcpy((void *)img->dst, (const void *)(img->offset + addr), 179 img->size); 180 181 s = img->dst & ~(CONFIG_SYS_CACHELINE_SIZE - 1); 182 e = ALIGN(img->dst + img->size, CONFIG_SYS_CACHELINE_SIZE) - 1; 183 184 flush_dcache_range(s, e); 185 186#ifdef CONFIG_ARMV8_CE_SHA256 187 if (((img->hab_flags & AHAB_HASH_TYPE_MASK) >> 8) == AHAB_HASH_TYPE_SHA256) { 188 sha256_csum_wd((void *)img->dst, img->size, hash_value, CHUNKSZ_SHA256); 189 err = memcmp(&img->hash, &hash_value, SHA256_SUM_LEN); 190 if (err) { 191 printf("img %d hash comparison failed, error %d\n", i, err); 192 ret = -EIO; 193 goto exit; 194 } 195 } else { 196#endif 197 ret = ahab_verify_cntr_image(img, i); 198 if (ret) 199 goto exit; 200#ifdef CONFIG_ARMV8_CE_SHA256 201 } 202#endif 203 } 204 205exit: 206 ahab_auth_release(); 207 208 return ret; 209} 210 211static int do_authenticate(struct cmd_tbl *cmdtp, int flag, int argc, 212 char *const argv[]) 213{ 214 ulong addr; 215 216 if (argc < 2) 217 return CMD_RET_USAGE; 218 219 addr = hextoul(argv[1], NULL); 220 221 printf("Authenticate OS container at 0x%lx\n", addr); 222 223 if (authenticate_os_container(addr)) 224 return CMD_RET_FAILURE; 225 226 return CMD_RET_SUCCESS; 227} 228 229static void display_life_cycle(u16 lc) 230{ 231 printf("Lifecycle: 0x%04X, ", lc); 232 switch (lc) { 233 case 0x1: 234 printf("Pristine\n\n"); 235 break; 236 case 0x2: 237 printf("Fab\n\n"); 238 break; 239 case 0x8: 240 printf("Open\n\n"); 241 break; 242 case 0x20: 243 printf("NXP closed\n\n"); 244 break; 245 case 0x80: 246 printf("OEM closed\n\n"); 247 break; 248 case 0x100: 249 printf("Partial field return\n\n"); 250 break; 251 case 0x200: 252 printf("Full field return\n\n"); 253 break; 254 case 0x400: 255 printf("No return\n\n"); 256 break; 257 default: 258 printf("Unknown\n\n"); 259 break; 260 } 261} 262 263#define AHAB_AUTH_CONTAINER_REQ 0x87 264#define AHAB_VERIFY_IMAGE_REQ 0x88 265 266#define AHAB_NO_AUTHENTICATION_IND 0xee 267#define AHAB_BAD_KEY_HASH_IND 0xfa 268#define AHAB_INVALID_KEY_IND 0xf9 269#define AHAB_BAD_SIGNATURE_IND 0xf0 270#define AHAB_BAD_HASH_IND 0xf1 271 272static void display_ahab_auth_event(u32 event) 273{ 274 u8 cmd = (event >> 16) & 0xff; 275 u8 resp_ind = (event >> 8) & 0xff; 276 277 switch (cmd) { 278 case AHAB_AUTH_CONTAINER_REQ: 279 printf("\tCMD = AHAB_AUTH_CONTAINER_REQ (0x%02X)\n", cmd); 280 printf("\tIND = "); 281 break; 282 case AHAB_VERIFY_IMAGE_REQ: 283 printf("\tCMD = AHAB_VERIFY_IMAGE_REQ (0x%02X)\n", cmd); 284 printf("\tIND = "); 285 break; 286 default: 287 return; 288 } 289 290 switch (resp_ind) { 291 case AHAB_NO_AUTHENTICATION_IND: 292 printf("AHAB_NO_AUTHENTICATION_IND (0x%02X)\n\n", resp_ind); 293 break; 294 case AHAB_BAD_KEY_HASH_IND: 295 printf("AHAB_BAD_KEY_HASH_IND (0x%02X)\n\n", resp_ind); 296 break; 297 case AHAB_INVALID_KEY_IND: 298 printf("AHAB_INVALID_KEY_IND (0x%02X)\n\n", resp_ind); 299 break; 300 case AHAB_BAD_SIGNATURE_IND: 301 printf("AHAB_BAD_SIGNATURE_IND (0x%02X)\n\n", resp_ind); 302 break; 303 case AHAB_BAD_HASH_IND: 304 printf("AHAB_BAD_HASH_IND (0x%02X)\n\n", resp_ind); 305 break; 306 default: 307 printf("Unknown Indicator (0x%02X)\n\n", resp_ind); 308 break; 309 } 310} 311 312static int do_ahab_status(struct cmd_tbl *cmdtp, int flag, int argc, 313 char *const argv[]) 314{ 315 int err; 316 u8 idx = 0U; 317 u32 event; 318 u16 lc; 319 320 err = sc_seco_chip_info(-1, &lc, NULL, NULL, NULL); 321 if (err) { 322 printf("Error in get lifecycle\n"); 323 return -EIO; 324 } 325 326 display_life_cycle(lc); 327 328 err = sc_seco_get_event(-1, idx, &event); 329 while (!err) { 330 printf("SECO Event[%u] = 0x%08X\n", idx, event); 331 display_ahab_auth_event(event); 332 333 idx++; 334 err = sc_seco_get_event(-1, idx, &event); 335 } 336 337 if (idx == 0) 338 printf("No SECO Events Found!\n\n"); 339 340 return 0; 341} 342 343int ahab_close(void) 344{ 345 int err; 346 u16 lc; 347 348 err = sc_seco_chip_info(-1, &lc, NULL, NULL, NULL); 349 if (err != SC_ERR_NONE) { 350 printf("Error in get lifecycle\n"); 351 return -EIO; 352 } 353 354 if (lc != 0x20) { 355 puts("Current lifecycle is NOT NXP closed, can't move to OEM closed\n"); 356 display_life_cycle(lc); 357 return -EPERM; 358 } 359 360 err = sc_seco_forward_lifecycle(-1, 16); 361 if (err != SC_ERR_NONE) { 362 printf("Error in forward lifecycle to OEM closed\n"); 363 return -EIO; 364 } 365 366 return 0; 367} 368 369static int confirm_close(void) 370{ 371 puts("Warning: Please ensure your sample is in NXP closed state, " 372 "OEM SRK hash has been fused, \n" 373 " and you are able to boot a signed image successfully " 374 "without any SECO events reported.\n" 375 " If not, your sample will be unrecoverable.\n" 376 "\nReally perform this operation? <y/N>\n"); 377 378 if (confirm_yesno()) 379 return 1; 380 381 puts("Ahab close aborted\n"); 382 return 0; 383} 384 385static int do_ahab_close(struct cmd_tbl *cmdtp, int flag, int argc, 386 char *const argv[]) 387{ 388 int confirmed = argc >= 2 && !strcmp(argv[1], "-y"); 389 int err; 390 391 if (!confirmed && !confirm_close()) 392 return -EACCES; 393 394 err = ahab_close(); 395 if (err) { 396 printf("Change to OEM closed failed\n"); 397 return err; 398 } 399 400 printf("Change to OEM closed successfully\n"); 401 402 return 0; 403} 404 405U_BOOT_CMD(auth_cntr, CONFIG_SYS_MAXARGS, 1, do_authenticate, 406 "autenticate OS container via AHAB", 407 "addr\n" 408 "addr - OS container hex address\n" 409); 410 411U_BOOT_CMD(ahab_status, CONFIG_SYS_MAXARGS, 1, do_ahab_status, 412 "display AHAB lifecycle and events from seco", 413 "" 414); 415 416U_BOOT_CMD(ahab_close, CONFIG_SYS_MAXARGS, 1, do_ahab_close, 417 "Change AHAB lifecycle to OEM closed", 418 "" 419); 420