scm.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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. #include <linux/slab.h>
  18. #include <linux/io.h>
  19. #include <linux/module.h>
  20. #include <linux/mutex.h>
  21. #include <linux/errno.h>
  22. #include <linux/err.h>
  23. #include <asm/outercache.h>
  24. #include <asm/cacheflush.h>
  25. #include "scm.h"
  26. #define SCM_ENOMEM -5
  27. #define SCM_EOPNOTSUPP -4
  28. #define SCM_EINVAL_ADDR -3
  29. #define SCM_EINVAL_ARG -2
  30. #define SCM_ERROR -1
  31. #define SCM_INTERRUPTED 1
  32. static DEFINE_MUTEX(scm_lock);
  33. /**
  34. * struct scm_command - one SCM command buffer
  35. * @len: total available memory for command and response
  36. * @buf_offset: start of command buffer
  37. * @resp_hdr_offset: start of response buffer
  38. * @id: command to be executed
  39. * @buf: buffer returned from scm_get_command_buffer()
  40. *
  41. * An SCM command is laid out in memory as follows:
  42. *
  43. * ------------------- <--- struct scm_command
  44. * | command header |
  45. * ------------------- <--- scm_get_command_buffer()
  46. * | command buffer |
  47. * ------------------- <--- struct scm_response and
  48. * | response header | scm_command_to_response()
  49. * ------------------- <--- scm_get_response_buffer()
  50. * | response buffer |
  51. * -------------------
  52. *
  53. * There can be arbitrary padding between the headers and buffers so
  54. * you should always use the appropriate scm_get_*_buffer() routines
  55. * to access the buffers in a safe manner.
  56. */
  57. struct scm_command {
  58. __le32 len;
  59. __le32 buf_offset;
  60. __le32 resp_hdr_offset;
  61. __le32 id;
  62. __le32 buf[0];
  63. };
  64. /**
  65. * struct scm_response - one SCM response buffer
  66. * @len: total available memory for response
  67. * @buf_offset: start of response data relative to start of scm_response
  68. * @is_complete: indicates if the command has finished processing
  69. */
  70. struct scm_response {
  71. __le32 len;
  72. __le32 buf_offset;
  73. __le32 is_complete;
  74. };
  75. /**
  76. * alloc_scm_command() - Allocate an SCM command
  77. * @cmd_size: size of the command buffer
  78. * @resp_size: size of the response buffer
  79. *
  80. * Allocate an SCM command, including enough room for the command
  81. * and response headers as well as the command and response buffers.
  82. *
  83. * Returns a valid &scm_command on success or %NULL if the allocation fails.
  84. */
  85. static struct scm_command *alloc_scm_command(size_t cmd_size, size_t resp_size)
  86. {
  87. struct scm_command *cmd;
  88. size_t len = sizeof(*cmd) + sizeof(struct scm_response) + cmd_size +
  89. resp_size;
  90. u32 offset;
  91. cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
  92. if (cmd) {
  93. cmd->len = cpu_to_le32(len);
  94. offset = offsetof(struct scm_command, buf);
  95. cmd->buf_offset = cpu_to_le32(offset);
  96. cmd->resp_hdr_offset = cpu_to_le32(offset + cmd_size);
  97. }
  98. return cmd;
  99. }
  100. /**
  101. * free_scm_command() - Free an SCM command
  102. * @cmd: command to free
  103. *
  104. * Free an SCM command.
  105. */
  106. static inline void free_scm_command(struct scm_command *cmd)
  107. {
  108. kfree(cmd);
  109. }
  110. /**
  111. * scm_command_to_response() - Get a pointer to a scm_response
  112. * @cmd: command
  113. *
  114. * Returns a pointer to a response for a command.
  115. */
  116. static inline struct scm_response *scm_command_to_response(
  117. const struct scm_command *cmd)
  118. {
  119. return (void *)cmd + le32_to_cpu(cmd->resp_hdr_offset);
  120. }
  121. /**
  122. * scm_get_command_buffer() - Get a pointer to a command buffer
  123. * @cmd: command
  124. *
  125. * Returns a pointer to the command buffer of a command.
  126. */
  127. static inline void *scm_get_command_buffer(const struct scm_command *cmd)
  128. {
  129. return (void *)cmd->buf;
  130. }
  131. /**
  132. * scm_get_response_buffer() - Get a pointer to a response buffer
  133. * @rsp: response
  134. *
  135. * Returns a pointer to a response buffer of a response.
  136. */
  137. static inline void *scm_get_response_buffer(const struct scm_response *rsp)
  138. {
  139. return (void *)rsp + le32_to_cpu(rsp->buf_offset);
  140. }
  141. static int scm_remap_error(int err)
  142. {
  143. pr_err("scm_call failed with error code %d\n", err);
  144. switch (err) {
  145. case SCM_ERROR:
  146. return -EIO;
  147. case SCM_EINVAL_ADDR:
  148. case SCM_EINVAL_ARG:
  149. return -EINVAL;
  150. case SCM_EOPNOTSUPP:
  151. return -EOPNOTSUPP;
  152. case SCM_ENOMEM:
  153. return -ENOMEM;
  154. }
  155. return -EINVAL;
  156. }
  157. static u32 smc(u32 cmd_addr)
  158. {
  159. int context_id;
  160. register u32 r0 asm("r0") = 1;
  161. register u32 r1 asm("r1") = (u32)&context_id;
  162. register u32 r2 asm("r2") = cmd_addr;
  163. do {
  164. asm volatile(
  165. __asmeq("%0", "r0")
  166. __asmeq("%1", "r0")
  167. __asmeq("%2", "r1")
  168. __asmeq("%3", "r2")
  169. #ifdef REQUIRES_SEC
  170. ".arch_extension sec\n"
  171. #endif
  172. "smc #0 @ switch to secure world\n"
  173. : "=r" (r0)
  174. : "r" (r0), "r" (r1), "r" (r2)
  175. : "r3");
  176. } while (r0 == SCM_INTERRUPTED);
  177. return r0;
  178. }
  179. static int __scm_call(const struct scm_command *cmd)
  180. {
  181. int ret;
  182. u32 cmd_addr = virt_to_phys(cmd);
  183. /*
  184. * Flush the command buffer so that the secure world sees
  185. * the correct data.
  186. */
  187. __cpuc_flush_dcache_area((void *)cmd, cmd->len);
  188. outer_flush_range(cmd_addr, cmd_addr + cmd->len);
  189. ret = smc(cmd_addr);
  190. if (ret < 0)
  191. ret = scm_remap_error(ret);
  192. return ret;
  193. }
  194. static void scm_inv_range(unsigned long start, unsigned long end)
  195. {
  196. u32 cacheline_size, ctr;
  197. asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr));
  198. cacheline_size = 4 << ((ctr >> 16) & 0xf);
  199. start = round_down(start, cacheline_size);
  200. end = round_up(end, cacheline_size);
  201. outer_inv_range(start, end);
  202. while (start < end) {
  203. asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (start)
  204. : "memory");
  205. start += cacheline_size;
  206. }
  207. dsb();
  208. isb();
  209. }
  210. /**
  211. * scm_call() - Send an SCM command
  212. * @svc_id: service identifier
  213. * @cmd_id: command identifier
  214. * @cmd_buf: command buffer
  215. * @cmd_len: length of the command buffer
  216. * @resp_buf: response buffer
  217. * @resp_len: length of the response buffer
  218. *
  219. * Sends a command to the SCM and waits for the command to finish processing.
  220. *
  221. * A note on cache maintenance:
  222. * Note that any buffers that are expected to be accessed by the secure world
  223. * must be flushed before invoking scm_call and invalidated in the cache
  224. * immediately after scm_call returns. Cache maintenance on the command and
  225. * response buffers is taken care of by scm_call; however, callers are
  226. * responsible for any other cached buffers passed over to the secure world.
  227. */
  228. int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
  229. void *resp_buf, size_t resp_len)
  230. {
  231. int ret;
  232. struct scm_command *cmd;
  233. struct scm_response *rsp;
  234. unsigned long start, end;
  235. cmd = alloc_scm_command(cmd_len, resp_len);
  236. if (!cmd)
  237. return -ENOMEM;
  238. cmd->id = cpu_to_le32((svc_id << 10) | cmd_id);
  239. if (cmd_buf)
  240. memcpy(scm_get_command_buffer(cmd), cmd_buf, cmd_len);
  241. mutex_lock(&scm_lock);
  242. ret = __scm_call(cmd);
  243. mutex_unlock(&scm_lock);
  244. if (ret)
  245. goto out;
  246. rsp = scm_command_to_response(cmd);
  247. start = (unsigned long)rsp;
  248. do {
  249. scm_inv_range(start, start + sizeof(*rsp));
  250. } while (!rsp->is_complete);
  251. end = (unsigned long)scm_get_response_buffer(rsp) + resp_len;
  252. scm_inv_range(start, end);
  253. if (resp_buf)
  254. memcpy(resp_buf, scm_get_response_buffer(rsp), resp_len);
  255. out:
  256. free_scm_command(cmd);
  257. return ret;
  258. }
  259. EXPORT_SYMBOL(scm_call);
  260. u32 scm_get_version(void)
  261. {
  262. int context_id;
  263. static u32 version = -1;
  264. register u32 r0 asm("r0");
  265. register u32 r1 asm("r1");
  266. if (version != -1)
  267. return version;
  268. mutex_lock(&scm_lock);
  269. r0 = 0x1 << 8;
  270. r1 = (u32)&context_id;
  271. do {
  272. asm volatile(
  273. __asmeq("%0", "r0")
  274. __asmeq("%1", "r1")
  275. __asmeq("%2", "r0")
  276. __asmeq("%3", "r1")
  277. #ifdef REQUIRES_SEC
  278. ".arch_extension sec\n"
  279. #endif
  280. "smc #0 @ switch to secure world\n"
  281. : "=r" (r0), "=r" (r1)
  282. : "r" (r0), "r" (r1)
  283. : "r2", "r3");
  284. } while (r0 == SCM_INTERRUPTED);
  285. version = r1;
  286. mutex_unlock(&scm_lock);
  287. return version;
  288. }
  289. EXPORT_SYMBOL(scm_get_version);