1 /* 2 * Copyright (C) 2013 Broadcom Corporation 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation version 2. 7 * 8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 9 * kind, whether express or implied; without even the implied warranty 10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #include <stdarg.h> 15 #include <linux/smp.h> 16 #include <linux/io.h> 17 #include <linux/ioport.h> 18 19 #include <asm/cacheflush.h> 20 #include <linux/of_address.h> 21 22 #include "bcm_kona_smc.h" 23 24 static u32 bcm_smc_buffer_phys; /* physical address */ 25 static void __iomem *bcm_smc_buffer; /* virtual address */ 26 27 struct bcm_kona_smc_data { 28 unsigned service_id; 29 unsigned arg0; 30 unsigned arg1; 31 unsigned arg2; 32 unsigned arg3; 33 unsigned result; 34 }; 35 36 static const struct of_device_id bcm_kona_smc_ids[] __initconst = { 37 {.compatible = "brcm,kona-smc"}, 38 {.compatible = "bcm,kona-smc"}, /* deprecated name */ 39 {}, 40 }; 41 42 /* Map in the args buffer area */ 43 int __init bcm_kona_smc_init(void) 44 { 45 struct device_node *node; 46 const __be32 *prop_val; 47 u64 prop_size = 0; 48 unsigned long buffer_size; 49 u32 buffer_phys; 50 51 /* Read buffer addr and size from the device tree node */ 52 node = of_find_matching_node(NULL, bcm_kona_smc_ids); 53 if (!node) 54 return -ENODEV; 55 56 prop_val = of_get_address(node, 0, &prop_size, NULL); 57 if (!prop_val) 58 return -EINVAL; 59 60 /* We assume space for four 32-bit arguments */ 61 if (prop_size < 4 * sizeof(u32) || prop_size > (u64)ULONG_MAX) 62 return -EINVAL; 63 buffer_size = (unsigned long)prop_size; 64 65 buffer_phys = be32_to_cpup(prop_val); 66 if (!buffer_phys) 67 return -EINVAL; 68 69 bcm_smc_buffer = ioremap(buffer_phys, buffer_size); 70 if (!bcm_smc_buffer) 71 return -ENOMEM; 72 bcm_smc_buffer_phys = buffer_phys; 73 74 pr_info("Kona Secure API initialized\n"); 75 76 return 0; 77 } 78 79 /* 80 * int bcm_kona_do_smc(u32 service_id, u32 buffer_addr) 81 * 82 * Only core 0 can run the secure monitor code. If an "smc" request 83 * is initiated on a different core it must be redirected to core 0 84 * for execution. We rely on the caller to handle this. 85 * 86 * Each "smc" request supplies a service id and the address of a 87 * buffer containing parameters related to the service to be 88 * performed. A flags value defines the behavior of the level 2 89 * cache and interrupt handling while the secure monitor executes. 90 * 91 * Parameters to the "smc" request are passed in r4-r6 as follows: 92 * r4 service id 93 * r5 flags (SEC_ROM_*) 94 * r6 physical address of buffer with other parameters 95 * 96 * Execution of an "smc" request produces two distinct results. 97 * 98 * First, the secure monitor call itself (regardless of the specific 99 * service request) can succeed, or can produce an error. When an 100 * "smc" request completes this value is found in r12; it should 101 * always be SEC_EXIT_NORMAL. 102 * 103 * In addition, the particular service performed produces a result. 104 * The values that should be expected depend on the service. We 105 * therefore return this value to the caller, so it can handle the 106 * request result appropriately. This result value is found in r0 107 * when the "smc" request completes. 108 */ 109 static int bcm_kona_do_smc(u32 service_id, u32 buffer_phys) 110 { 111 register u32 ip asm("ip"); /* Also called r12 */ 112 register u32 r0 asm("r0"); 113 register u32 r4 asm("r4"); 114 register u32 r5 asm("r5"); 115 register u32 r6 asm("r6"); 116 117 r4 = service_id; 118 r5 = 0x3; /* Keep IRQ and FIQ off in SM */ 119 r6 = buffer_phys; 120 121 asm volatile ( 122 /* Make sure we got the registers we want */ 123 __asmeq("%0", "ip") 124 __asmeq("%1", "r0") 125 __asmeq("%2", "r4") 126 __asmeq("%3", "r5") 127 __asmeq("%4", "r6") 128 ".arch_extension sec\n" 129 " smc #0\n" 130 : "=r" (ip), "=r" (r0) 131 : "r" (r4), "r" (r5), "r" (r6) 132 : "r1", "r2", "r3", "r7", "lr"); 133 134 BUG_ON(ip != SEC_EXIT_NORMAL); 135 136 return r0; 137 } 138 139 /* __bcm_kona_smc() should only run on CPU 0, with pre-emption disabled */ 140 static void __bcm_kona_smc(void *info) 141 { 142 struct bcm_kona_smc_data *data = info; 143 u32 __iomem *args = bcm_smc_buffer; 144 145 BUG_ON(smp_processor_id() != 0); 146 BUG_ON(!args); 147 148 /* Copy the four 32 bit argument values into the bounce area */ 149 writel_relaxed(data->arg0, args++); 150 writel_relaxed(data->arg1, args++); 151 writel_relaxed(data->arg2, args++); 152 writel(data->arg3, args); 153 154 /* Flush caches for input data passed to Secure Monitor */ 155 flush_cache_all(); 156 157 /* Trap into Secure Monitor and record the request result */ 158 data->result = bcm_kona_do_smc(data->service_id, bcm_smc_buffer_phys); 159 } 160 161 unsigned bcm_kona_smc(unsigned service_id, unsigned arg0, unsigned arg1, 162 unsigned arg2, unsigned arg3) 163 { 164 struct bcm_kona_smc_data data; 165 166 data.service_id = service_id; 167 data.arg0 = arg0; 168 data.arg1 = arg1; 169 data.arg2 = arg2; 170 data.arg3 = arg3; 171 data.result = 0; 172 173 /* 174 * Due to a limitation of the secure monitor, we must use the SMP 175 * infrastructure to forward all secure monitor calls to Core 0. 176 */ 177 smp_call_function_single(0, __bcm_kona_smc, &data, 1); 178 179 return data.result; 180 } 181