1/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. 2 * 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License version 2 and 5 * only version 2 as published by the Free Software Foundation. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 15 * 02110-1301, USA. 16 */ 17 18#include <linux/slab.h> 19#include <linux/io.h> 20#include <linux/module.h> 21#include <linux/mutex.h> 22#include <linux/errno.h> 23#include <linux/err.h> 24 25#include <asm/cacheflush.h> 26 27#include "scm.h" 28 29/* Cache line size for msm8x60 */ 30#define CACHELINESIZE 32 31 32#define SCM_ENOMEM -5 33#define SCM_EOPNOTSUPP -4 34#define SCM_EINVAL_ADDR -3 35#define SCM_EINVAL_ARG -2 36#define SCM_ERROR -1 37#define SCM_INTERRUPTED 1 38 39static DEFINE_MUTEX(scm_lock); 40 41/** 42 * struct scm_command - one SCM command buffer 43 * @len: total available memory for command and response 44 * @buf_offset: start of command buffer 45 * @resp_hdr_offset: start of response buffer 46 * @id: command to be executed 47 * @buf: buffer returned from scm_get_command_buffer() 48 * 49 * An SCM command is laid out in memory as follows: 50 * 51 * ------------------- <--- struct scm_command 52 * | command header | 53 * ------------------- <--- scm_get_command_buffer() 54 * | command buffer | 55 * ------------------- <--- struct scm_response and 56 * | response header | scm_command_to_response() 57 * ------------------- <--- scm_get_response_buffer() 58 * | response buffer | 59 * ------------------- 60 * 61 * There can be arbitrary padding between the headers and buffers so 62 * you should always use the appropriate scm_get_*_buffer() routines 63 * to access the buffers in a safe manner. 64 */ 65struct scm_command { 66 u32 len; 67 u32 buf_offset; 68 u32 resp_hdr_offset; 69 u32 id; 70 u32 buf[0]; 71}; 72 73/** 74 * struct scm_response - one SCM response buffer 75 * @len: total available memory for response 76 * @buf_offset: start of response data relative to start of scm_response 77 * @is_complete: indicates if the command has finished processing 78 */ 79struct scm_response { 80 u32 len; 81 u32 buf_offset; 82 u32 is_complete; 83}; 84 85/** 86 * alloc_scm_command() - Allocate an SCM command 87 * @cmd_size: size of the command buffer 88 * @resp_size: size of the response buffer 89 * 90 * Allocate an SCM command, including enough room for the command 91 * and response headers as well as the command and response buffers. 92 * 93 * Returns a valid &scm_command on success or %NULL if the allocation fails. 94 */ 95static struct scm_command *alloc_scm_command(size_t cmd_size, size_t resp_size) 96{ 97 struct scm_command *cmd; 98 size_t len = sizeof(*cmd) + sizeof(struct scm_response) + cmd_size + 99 resp_size; 100 101 cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL); 102 if (cmd) { 103 cmd->len = len; 104 cmd->buf_offset = offsetof(struct scm_command, buf); 105 cmd->resp_hdr_offset = cmd->buf_offset + cmd_size; 106 } 107 return cmd; 108} 109 110/** 111 * free_scm_command() - Free an SCM command 112 * @cmd: command to free 113 * 114 * Free an SCM command. 115 */ 116static inline void free_scm_command(struct scm_command *cmd) 117{ 118 kfree(cmd); 119} 120 121/** 122 * scm_command_to_response() - Get a pointer to a scm_response 123 * @cmd: command 124 * 125 * Returns a pointer to a response for a command. 126 */ 127static inline struct scm_response *scm_command_to_response( 128 const struct scm_command *cmd) 129{ 130 return (void *)cmd + cmd->resp_hdr_offset; 131} 132 133/** 134 * scm_get_command_buffer() - Get a pointer to a command buffer 135 * @cmd: command 136 * 137 * Returns a pointer to the command buffer of a command. 138 */ 139static inline void *scm_get_command_buffer(const struct scm_command *cmd) 140{ 141 return (void *)cmd->buf; 142} 143 144/** 145 * scm_get_response_buffer() - Get a pointer to a response buffer 146 * @rsp: response 147 * 148 * Returns a pointer to a response buffer of a response. 149 */ 150static inline void *scm_get_response_buffer(const struct scm_response *rsp) 151{ 152 return (void *)rsp + rsp->buf_offset; 153} 154 155static int scm_remap_error(int err) 156{ 157 switch (err) { 158 case SCM_ERROR: 159 return -EIO; 160 case SCM_EINVAL_ADDR: 161 case SCM_EINVAL_ARG: 162 return -EINVAL; 163 case SCM_EOPNOTSUPP: 164 return -EOPNOTSUPP; 165 case SCM_ENOMEM: 166 return -ENOMEM; 167 } 168 return -EINVAL; 169} 170 171static u32 smc(u32 cmd_addr) 172{ 173 int context_id; 174 register u32 r0 asm("r0") = 1; 175 register u32 r1 asm("r1") = (u32)&context_id; 176 register u32 r2 asm("r2") = cmd_addr; 177 do { 178 asm volatile( 179 __asmeq("%0", "r0") 180 __asmeq("%1", "r0") 181 __asmeq("%2", "r1") 182 __asmeq("%3", "r2") 183#ifdef REQUIRES_SEC 184 ".arch_extension sec\n" 185#endif 186 "smc #0 @ switch to secure world\n" 187 : "=r" (r0) 188 : "r" (r0), "r" (r1), "r" (r2) 189 : "r3"); 190 } while (r0 == SCM_INTERRUPTED); 191 192 return r0; 193} 194 195static int __scm_call(const struct scm_command *cmd) 196{ 197 int ret; 198 u32 cmd_addr = virt_to_phys(cmd); 199 200 /* 201 * Flush the entire cache here so callers don't have to remember 202 * to flush the cache when passing physical addresses to the secure 203 * side in the buffer. 204 */ 205 flush_cache_all(); 206 ret = smc(cmd_addr); 207 if (ret < 0) 208 ret = scm_remap_error(ret); 209 210 return ret; 211} 212 213/** 214 * scm_call() - Send an SCM command 215 * @svc_id: service identifier 216 * @cmd_id: command identifier 217 * @cmd_buf: command buffer 218 * @cmd_len: length of the command buffer 219 * @resp_buf: response buffer 220 * @resp_len: length of the response buffer 221 * 222 * Sends a command to the SCM and waits for the command to finish processing. 223 */ 224int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len, 225 void *resp_buf, size_t resp_len) 226{ 227 int ret; 228 struct scm_command *cmd; 229 struct scm_response *rsp; 230 231 cmd = alloc_scm_command(cmd_len, resp_len); 232 if (!cmd) 233 return -ENOMEM; 234 235 cmd->id = (svc_id << 10) | cmd_id; 236 if (cmd_buf) 237 memcpy(scm_get_command_buffer(cmd), cmd_buf, cmd_len); 238 239 mutex_lock(&scm_lock); 240 ret = __scm_call(cmd); 241 mutex_unlock(&scm_lock); 242 if (ret) 243 goto out; 244 245 rsp = scm_command_to_response(cmd); 246 do { 247 u32 start = (u32)rsp; 248 u32 end = (u32)scm_get_response_buffer(rsp) + resp_len; 249 start &= ~(CACHELINESIZE - 1); 250 while (start < end) { 251 asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start) 252 : "memory"); 253 start += CACHELINESIZE; 254 } 255 } while (!rsp->is_complete); 256 257 if (resp_buf) 258 memcpy(resp_buf, scm_get_response_buffer(rsp), resp_len); 259out: 260 free_scm_command(cmd); 261 return ret; 262} 263EXPORT_SYMBOL(scm_call); 264 265u32 scm_get_version(void) 266{ 267 int context_id; 268 static u32 version = -1; 269 register u32 r0 asm("r0"); 270 register u32 r1 asm("r1"); 271 272 if (version != -1) 273 return version; 274 275 mutex_lock(&scm_lock); 276 277 r0 = 0x1 << 8; 278 r1 = (u32)&context_id; 279 do { 280 asm volatile( 281 __asmeq("%0", "r0") 282 __asmeq("%1", "r1") 283 __asmeq("%2", "r0") 284 __asmeq("%3", "r1") 285 "smc #0 @ switch to secure world\n" 286 : "=r" (r0), "=r" (r1) 287 : "r" (r0), "r" (r1) 288 : "r2", "r3"); 289 } while (r0 == SCM_INTERRUPTED); 290 291 version = r1; 292 mutex_unlock(&scm_lock); 293 294 return version; 295} 296EXPORT_SYMBOL(scm_get_version); 297