Andreas Dannenberg | 6469e1a | 2016-06-27 09:19:18 -0500 | [diff] [blame] | 1 | /* |
| 2 | * |
| 3 | * Common security related functions for OMAP devices |
| 4 | * |
| 5 | * (C) Copyright 2016 |
| 6 | * Texas Instruments, <www.ti.com> |
| 7 | * |
| 8 | * Daniel Allred <d-allred@ti.com> |
| 9 | * Andreas Dannenberg <dannenberg@ti.com> |
| 10 | * |
| 11 | * SPDX-License-Identifier: GPL-2.0+ |
| 12 | */ |
| 13 | |
| 14 | #include <common.h> |
| 15 | #include <stdarg.h> |
| 16 | |
| 17 | #include <asm/arch/sys_proto.h> |
| 18 | #include <asm/omap_common.h> |
| 19 | #include <asm/omap_sec_common.h> |
Andreas Dannenberg | 1549e2f | 2016-06-27 09:19:19 -0500 | [diff] [blame] | 20 | #include <asm/spl.h> |
| 21 | #include <spl.h> |
| 22 | |
| 23 | /* Index for signature verify ROM API */ |
| 24 | #define API_HAL_KM_VERIFYCERTIFICATESIGNATURE_INDEX (0x0000000E) |
Andreas Dannenberg | 6469e1a | 2016-06-27 09:19:18 -0500 | [diff] [blame] | 25 | |
| 26 | static uint32_t secure_rom_call_args[5] __aligned(ARCH_DMA_MINALIGN); |
| 27 | |
| 28 | u32 secure_rom_call(u32 service, u32 proc_id, u32 flag, ...) |
| 29 | { |
| 30 | int i; |
| 31 | u32 num_args; |
| 32 | va_list ap; |
| 33 | |
| 34 | va_start(ap, flag); |
| 35 | |
| 36 | num_args = va_arg(ap, u32); |
| 37 | |
| 38 | if (num_args > 4) |
| 39 | return 1; |
| 40 | |
| 41 | /* Copy args to aligned args structure */ |
| 42 | for (i = 0; i < num_args; i++) |
| 43 | secure_rom_call_args[i + 1] = va_arg(ap, u32); |
| 44 | |
| 45 | secure_rom_call_args[0] = num_args; |
| 46 | |
| 47 | va_end(ap); |
| 48 | |
| 49 | /* if data cache is enabled, flush the aligned args structure */ |
| 50 | flush_dcache_range( |
| 51 | (unsigned int)&secure_rom_call_args[0], |
| 52 | (unsigned int)&secure_rom_call_args[0] + |
| 53 | roundup(sizeof(secure_rom_call_args), ARCH_DMA_MINALIGN)); |
| 54 | |
| 55 | return omap_smc_sec(service, proc_id, flag, secure_rom_call_args); |
| 56 | } |
Andreas Dannenberg | 1549e2f | 2016-06-27 09:19:19 -0500 | [diff] [blame] | 57 | |
| 58 | static u32 find_sig_start(char *image, size_t size) |
| 59 | { |
| 60 | char *image_end = image + size; |
| 61 | char *sig_start_magic = "CERT_"; |
| 62 | int magic_str_len = strlen(sig_start_magic); |
| 63 | char *ch; |
| 64 | |
| 65 | while (--image_end > image) { |
| 66 | if (*image_end == '_') { |
| 67 | ch = image_end - magic_str_len + 1; |
| 68 | if (!strncmp(ch, sig_start_magic, magic_str_len)) |
| 69 | return (u32)ch; |
| 70 | } |
| 71 | } |
| 72 | return 0; |
| 73 | } |
| 74 | |
| 75 | int secure_boot_verify_image(void **image, size_t *size) |
| 76 | { |
| 77 | int result = 1; |
| 78 | u32 cert_addr, sig_addr; |
| 79 | size_t cert_size; |
| 80 | |
| 81 | /* Perform cache writeback on input buffer */ |
| 82 | flush_dcache_range( |
| 83 | (u32)*image, |
| 84 | (u32)*image + roundup(*size, ARCH_DMA_MINALIGN)); |
| 85 | |
| 86 | cert_addr = (uint32_t)*image; |
| 87 | sig_addr = find_sig_start((char *)*image, *size); |
| 88 | |
| 89 | if (sig_addr == 0) { |
| 90 | printf("No signature found in image!\n"); |
| 91 | result = 1; |
| 92 | goto auth_exit; |
| 93 | } |
| 94 | |
| 95 | *size = sig_addr - cert_addr; /* Subtract out the signature size */ |
| 96 | cert_size = *size; |
| 97 | |
| 98 | /* Check if image load address is 32-bit aligned */ |
| 99 | if (!IS_ALIGNED(cert_addr, 4)) { |
| 100 | printf("Image is not 4-byte aligned!\n"); |
| 101 | result = 1; |
| 102 | goto auth_exit; |
| 103 | } |
| 104 | |
| 105 | /* Image size also should be multiple of 4 */ |
| 106 | if (!IS_ALIGNED(cert_size, 4)) { |
| 107 | printf("Image size is not 4-byte aligned!\n"); |
| 108 | result = 1; |
| 109 | goto auth_exit; |
| 110 | } |
| 111 | |
| 112 | /* Call ROM HAL API to verify certificate signature */ |
| 113 | debug("%s: load_addr = %x, size = %x, sig_addr = %x\n", __func__, |
| 114 | cert_addr, cert_size, sig_addr); |
| 115 | |
| 116 | result = secure_rom_call( |
| 117 | API_HAL_KM_VERIFYCERTIFICATESIGNATURE_INDEX, 0, 0, |
| 118 | 4, cert_addr, cert_size, sig_addr, 0xFFFFFFFF); |
| 119 | auth_exit: |
| 120 | if (result != 0) { |
| 121 | printf("Authentication failed!\n"); |
| 122 | printf("Return Value = %08X\n", result); |
| 123 | hang(); |
| 124 | } |
| 125 | |
| 126 | /* |
| 127 | * Output notification of successful authentication as well the name of |
| 128 | * the signing certificate used to re-assure the user that the secure |
| 129 | * code is being processed as expected. However suppress any such log |
| 130 | * output in case of building for SPL and booting via YMODEM. This is |
| 131 | * done to avoid disturbing the YMODEM serial protocol transactions. |
| 132 | */ |
| 133 | if (!(IS_ENABLED(CONFIG_SPL_BUILD) && |
| 134 | IS_ENABLED(CONFIG_SPL_YMODEM_SUPPORT) && |
| 135 | spl_boot_device() == BOOT_DEVICE_UART)) |
| 136 | printf("Authentication passed: %s\n", (char *)sig_addr); |
| 137 | |
| 138 | return result; |
| 139 | } |