trusty.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. /*
  2. * Copyright (C) 2013 Google, Inc.
  3. *
  4. * This software is licensed under the terms of the GNU General Public
  5. * License version 2, as published by the Free Software Foundation, and
  6. * may be copied, distributed, and modified under those terms.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. */
  14. #include <asm/compiler.h>
  15. #include <linux/delay.h>
  16. #include <linux/of.h>
  17. #include <linux/of_platform.h>
  18. #include <linux/platform_device.h>
  19. #ifdef CONFIG_MT_TRUSTY_DEBUGFS
  20. #include <linux/random.h>
  21. #endif
  22. #include <linux/slab.h>
  23. #include <linux/stat.h>
  24. #include <linux/string.h>
  25. #include <linux/trusty/smcall.h>
  26. #include <linux/trusty/sm_err.h>
  27. #include <linux/trusty/trusty.h>
  28. struct trusty_state {
  29. struct mutex smc_lock;
  30. struct atomic_notifier_head notifier;
  31. struct completion cpu_idle_completion;
  32. char *version_str;
  33. u32 api_version;
  34. };
  35. #ifdef CONFIG_ARM64
  36. #define SMC_ARG0 "x0"
  37. #define SMC_ARG1 "x1"
  38. #define SMC_ARG2 "x2"
  39. #define SMC_ARG3 "x3"
  40. #define SMC_ARCH_EXTENSION ""
  41. #define SMC_REGISTERS_TRASHED "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", \
  42. "x12", "x13", "x14", "x15", "x16", "x17"
  43. #else
  44. #define SMC_ARG0 "r0"
  45. #define SMC_ARG1 "r1"
  46. #define SMC_ARG2 "r2"
  47. #define SMC_ARG3 "r3"
  48. #define SMC_ARCH_EXTENSION ".arch_extension sec\n"
  49. #define SMC_REGISTERS_TRASHED "ip"
  50. #endif
  51. static inline ulong smc(ulong r0, ulong r1, ulong r2, ulong r3)
  52. {
  53. register ulong _r0 asm(SMC_ARG0) = r0;
  54. register ulong _r1 asm(SMC_ARG1) = r1;
  55. register ulong _r2 asm(SMC_ARG2) = r2;
  56. register ulong _r3 asm(SMC_ARG3) = r3;
  57. asm volatile(
  58. __asmeq("%0", SMC_ARG0)
  59. __asmeq("%1", SMC_ARG1)
  60. __asmeq("%2", SMC_ARG2)
  61. __asmeq("%3", SMC_ARG3)
  62. __asmeq("%4", SMC_ARG0)
  63. __asmeq("%5", SMC_ARG1)
  64. __asmeq("%6", SMC_ARG2)
  65. __asmeq("%7", SMC_ARG3)
  66. SMC_ARCH_EXTENSION
  67. "smc #0" /* switch to secure world */
  68. : "=r" (_r0), "=r" (_r1), "=r" (_r2), "=r" (_r3)
  69. : "r" (_r0), "r" (_r1), "r" (_r2), "r" (_r3)
  70. : SMC_REGISTERS_TRASHED);
  71. return _r0;
  72. }
  73. s32 trusty_fast_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
  74. {
  75. struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
  76. BUG_ON(!s);
  77. BUG_ON(!SMC_IS_FASTCALL(smcnr));
  78. BUG_ON(SMC_IS_SMC64(smcnr));
  79. return smc(smcnr, a0, a1, a2);
  80. }
  81. EXPORT_SYMBOL(trusty_fast_call32);
  82. #ifdef CONFIG_64BIT
  83. s64 trusty_fast_call64(struct device *dev, u64 smcnr, u64 a0, u64 a1, u64 a2)
  84. {
  85. struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
  86. BUG_ON(!s);
  87. BUG_ON(!SMC_IS_FASTCALL(smcnr));
  88. BUG_ON(!SMC_IS_SMC64(smcnr));
  89. return smc(smcnr, a0, a1, a2);
  90. }
  91. #endif
  92. static ulong trusty_std_call_inner(struct device *dev, ulong smcnr,
  93. ulong a0, ulong a1, ulong a2)
  94. {
  95. ulong ret;
  96. int retry = 5;
  97. dev_dbg(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx)\n",
  98. __func__, smcnr, a0, a1, a2);
  99. while (true) {
  100. ret = smc(smcnr, a0, a1, a2);
  101. while ((s32)ret == SM_ERR_FIQ_INTERRUPTED)
  102. ret = smc(SMC_SC_RESTART_FIQ, 0, 0, 0);
  103. if ((int)ret != SM_ERR_BUSY || !retry)
  104. break;
  105. dev_dbg(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) returned busy, retry\n",
  106. __func__, smcnr, a0, a1, a2);
  107. retry--;
  108. }
  109. return ret;
  110. }
  111. static ulong trusty_std_call_helper(struct device *dev, ulong smcnr,
  112. ulong a0, ulong a1, ulong a2)
  113. {
  114. ulong ret;
  115. int sleep_time = 1;
  116. struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
  117. while (true) {
  118. local_irq_disable();
  119. atomic_notifier_call_chain(&s->notifier, TRUSTY_CALL_PREPARE,
  120. NULL);
  121. ret = trusty_std_call_inner(dev, smcnr, a0, a1, a2);
  122. atomic_notifier_call_chain(&s->notifier, TRUSTY_CALL_RETURNED,
  123. NULL);
  124. local_irq_enable();
  125. if ((int)ret != SM_ERR_BUSY)
  126. break;
  127. if (sleep_time == 256)
  128. dev_warn(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) returned busy\n",
  129. __func__, smcnr, a0, a1, a2);
  130. dev_dbg(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) returned busy, wait %d ms\n",
  131. __func__, smcnr, a0, a1, a2, sleep_time);
  132. msleep(sleep_time);
  133. if (sleep_time < 1000)
  134. sleep_time <<= 1;
  135. dev_dbg(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) retry\n",
  136. __func__, smcnr, a0, a1, a2);
  137. }
  138. if (sleep_time > 256)
  139. dev_warn(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx) busy cleared\n",
  140. __func__, smcnr, a0, a1, a2);
  141. return ret;
  142. }
  143. static void trusty_std_call_cpu_idle(struct trusty_state *s)
  144. {
  145. int ret;
  146. ret = wait_for_completion_timeout(&s->cpu_idle_completion, HZ * 10);
  147. if (!ret) {
  148. pr_warn("%s: timed out waiting for cpu idle to clear, retry anyway\n",
  149. __func__);
  150. }
  151. }
  152. s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
  153. {
  154. int ret;
  155. struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
  156. BUG_ON(SMC_IS_FASTCALL(smcnr));
  157. BUG_ON(SMC_IS_SMC64(smcnr));
  158. if (smcnr != SMC_SC_NOP) {
  159. mutex_lock(&s->smc_lock);
  160. reinit_completion(&s->cpu_idle_completion);
  161. }
  162. dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) started\n",
  163. __func__, smcnr, a0, a1, a2);
  164. ret = trusty_std_call_helper(dev, smcnr, a0, a1, a2);
  165. while (ret == SM_ERR_INTERRUPTED || ret == SM_ERR_CPU_IDLE) {
  166. dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) interrupted\n",
  167. __func__, smcnr, a0, a1, a2);
  168. if (ret == SM_ERR_CPU_IDLE)
  169. trusty_std_call_cpu_idle(s);
  170. ret = trusty_std_call_helper(dev, SMC_SC_RESTART_LAST, 0, 0, 0);
  171. }
  172. dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) returned 0x%x\n",
  173. __func__, smcnr, a0, a1, a2, ret);
  174. WARN_ONCE(ret == SM_ERR_PANIC, "trusty crashed");
  175. if (smcnr == SMC_SC_NOP)
  176. complete(&s->cpu_idle_completion);
  177. else
  178. mutex_unlock(&s->smc_lock);
  179. return ret;
  180. }
  181. EXPORT_SYMBOL(trusty_std_call32);
  182. int trusty_call_notifier_register(struct device *dev, struct notifier_block *n)
  183. {
  184. struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
  185. return atomic_notifier_chain_register(&s->notifier, n);
  186. }
  187. EXPORT_SYMBOL(trusty_call_notifier_register);
  188. int trusty_call_notifier_unregister(struct device *dev,
  189. struct notifier_block *n)
  190. {
  191. struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
  192. return atomic_notifier_chain_unregister(&s->notifier, n);
  193. }
  194. EXPORT_SYMBOL(trusty_call_notifier_unregister);
  195. static int trusty_remove_child(struct device *dev, void *data)
  196. {
  197. platform_device_unregister(to_platform_device(dev));
  198. return 0;
  199. }
  200. ssize_t trusty_version_show(struct device *dev, struct device_attribute *attr,
  201. char *buf)
  202. {
  203. struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
  204. return scnprintf(buf, PAGE_SIZE, "%s\n", s->version_str);
  205. }
  206. DEVICE_ATTR(trusty_version, S_IRUSR, trusty_version_show, NULL);
  207. #ifdef CONFIG_MT_TRUSTY_DEBUGFS
  208. ssize_t trusty_add(struct device *dev, struct device_attribute *attr,
  209. char *buf)
  210. {
  211. s32 a, b, ret;
  212. get_random_bytes(&a, sizeof(s32));
  213. a &= 0xFF;
  214. get_random_bytes(&b, sizeof(s32));
  215. b &= 0xFF;
  216. ret = trusty_std_call32(dev, MT_SMC_SC_ADD, a, b, 0);
  217. return scnprintf(buf, PAGE_SIZE, "%d + %d = %d, %s\n", a, b, ret,
  218. (a + b) == ret ? "PASS" : "FAIL");
  219. }
  220. DEVICE_ATTR(trusty_add, S_IRUSR, trusty_add, NULL);
  221. ssize_t trusty_threads(struct device *dev,
  222. struct device_attribute *attr, char *buf)
  223. {
  224. /* Dump Trusty threads info to memlog */
  225. trusty_fast_call32(dev, MT_SMC_FC_THREADS, 0, 0, 0);
  226. /* Dump threads info from memlog to kmsg*/
  227. trusty_std_call32(dev, SMC_SC_NOP, 0, 0, 0);
  228. return 0;
  229. }
  230. DEVICE_ATTR(trusty_threads, S_IRUSR, trusty_threads, NULL);
  231. ssize_t trusty_threadstats(struct device *dev,
  232. struct device_attribute *attr, char *buf)
  233. {
  234. /* Dump Trusty threads info to memlog */
  235. trusty_fast_call32(dev, MT_SMC_FC_THREADSTATS, 0, 0, 0);
  236. /* Dump threads info from memlog to kmsg*/
  237. trusty_std_call32(dev, SMC_SC_NOP, 0, 0, 0);
  238. return 0;
  239. }
  240. DEVICE_ATTR(trusty_threadstats, S_IRUSR, trusty_threadstats, NULL);
  241. ssize_t trusty_threadload(struct device *dev,
  242. struct device_attribute *attr, char *buf)
  243. {
  244. /* Dump Trusty threads info to memlog */
  245. trusty_fast_call32(dev, MT_SMC_FC_THREADLOAD, 0, 0, 0);
  246. /* Dump threads info from memlog to kmsg*/
  247. trusty_std_call32(dev, SMC_SC_NOP, 0, 0, 0);
  248. return 0;
  249. }
  250. DEVICE_ATTR(trusty_threadload, S_IRUSR, trusty_threadload, NULL);
  251. ssize_t trusty_heap_dump(struct device *dev,
  252. struct device_attribute *attr, char *buf)
  253. {
  254. /* Dump Trusty threads info to memlog */
  255. trusty_fast_call32(dev, MT_SMC_FC_HEAP_DUMP, 0, 0, 0);
  256. /* Dump threads info from memlog to kmsg*/
  257. trusty_std_call32(dev, SMC_SC_NOP, 0, 0, 0);
  258. return 0;
  259. }
  260. DEVICE_ATTR(trusty_heap_dump, S_IRUSR, trusty_heap_dump, NULL);
  261. ssize_t trusty_apps(struct device *dev,
  262. struct device_attribute *attr, char *buf)
  263. {
  264. /* Dump Trusty threads info to memlog */
  265. trusty_fast_call32(dev, MT_SMC_FC_APPS, 0, 0, 0);
  266. /* Dump threads info from memlog to kmsg*/
  267. trusty_std_call32(dev, SMC_SC_NOP, 0, 0, 0);
  268. return 0;
  269. }
  270. DEVICE_ATTR(trusty_apps, S_IRUSR, trusty_apps, NULL);
  271. ssize_t trusty_vdev_reset(struct device *dev,
  272. struct device_attribute *attr, char *buf)
  273. {
  274. trusty_std_call32(dev, SMC_SC_VDEV_RESET, 0, 0, 0);
  275. return 0;
  276. }
  277. DEVICE_ATTR(trusty_vdev_reset, S_IRUSR, trusty_vdev_reset, NULL);
  278. static void trusty_create_debugfs(struct trusty_state *s, struct device *pdev)
  279. {
  280. int ret;
  281. ret = device_create_file(pdev, &dev_attr_trusty_add);
  282. if (ret)
  283. goto err_create_trusty_add;
  284. ret = device_create_file(pdev, &dev_attr_trusty_threads);
  285. if (ret)
  286. goto err_create_trusty_threads;
  287. ret = device_create_file(pdev, &dev_attr_trusty_threadstats);
  288. if (ret)
  289. goto err_create_trusty_threadstats;
  290. ret = device_create_file(pdev, &dev_attr_trusty_threadload);
  291. if (ret)
  292. goto err_create_trusty_threadload;
  293. ret = device_create_file(pdev, &dev_attr_trusty_heap_dump);
  294. if (ret)
  295. goto err_create_trusty_heap_dump;
  296. ret = device_create_file(pdev, &dev_attr_trusty_apps);
  297. if (ret)
  298. goto err_create_trusty_apps;
  299. ret = device_create_file(pdev, &dev_attr_trusty_vdev_reset);
  300. if (ret)
  301. goto err_create_trusty_vdev_reset;
  302. return;
  303. err_create_trusty_vdev_reset:
  304. device_remove_file(pdev, &dev_attr_trusty_vdev_reset);
  305. err_create_trusty_apps:
  306. device_remove_file(pdev, &dev_attr_trusty_apps);
  307. err_create_trusty_heap_dump:
  308. device_remove_file(pdev, &dev_attr_trusty_heap_dump);
  309. err_create_trusty_threadload:
  310. device_remove_file(pdev, &dev_attr_trusty_threadload);
  311. err_create_trusty_threadstats:
  312. device_remove_file(pdev, &dev_attr_trusty_threadstats);
  313. err_create_trusty_threads:
  314. device_remove_file(pdev, &dev_attr_trusty_threads);
  315. err_create_trusty_add:
  316. device_remove_file(pdev, &dev_attr_trusty_add);
  317. }
  318. #endif /* CONFIG_MT_TRUSTY_DEBUGFS */
  319. const char *trusty_version_str_get(struct device *dev)
  320. {
  321. struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
  322. return s->version_str;
  323. }
  324. EXPORT_SYMBOL(trusty_version_str_get);
  325. static void trusty_init_version(struct trusty_state *s, struct device *dev)
  326. {
  327. int ret;
  328. int i;
  329. int version_str_len;
  330. ret = trusty_fast_call32(dev, SMC_FC_GET_VERSION_STR, -1, 0, 0);
  331. if (ret <= 0)
  332. goto err_get_size;
  333. version_str_len = ret;
  334. s->version_str = kmalloc(version_str_len + 1, GFP_KERNEL);
  335. for (i = 0; i < version_str_len; i++) {
  336. ret = trusty_fast_call32(dev, SMC_FC_GET_VERSION_STR, i, 0, 0);
  337. if (ret < 0)
  338. goto err_get_char;
  339. s->version_str[i] = ret;
  340. }
  341. s->version_str[i] = '\0';
  342. dev_info(dev, "trusty version: %s\n", s->version_str);
  343. ret = device_create_file(dev, &dev_attr_trusty_version);
  344. if (ret)
  345. goto err_create_file;
  346. return;
  347. err_create_file:
  348. err_get_char:
  349. kfree(s->version_str);
  350. s->version_str = NULL;
  351. err_get_size:
  352. dev_err(dev, "failed to get version: %d\n", ret);
  353. }
  354. u32 trusty_get_api_version(struct device *dev)
  355. {
  356. struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
  357. return s->api_version;
  358. }
  359. EXPORT_SYMBOL(trusty_get_api_version);
  360. static int trusty_init_api_version(struct trusty_state *s, struct device *dev)
  361. {
  362. u32 api_version;
  363. api_version = trusty_fast_call32(dev, SMC_FC_API_VERSION,
  364. TRUSTY_API_VERSION_CURRENT, 0, 0);
  365. if (api_version == SM_ERR_UNDEFINED_SMC)
  366. api_version = 0;
  367. if (api_version > TRUSTY_API_VERSION_CURRENT) {
  368. dev_err(dev, "unsupported api version %u > %u\n",
  369. api_version, TRUSTY_API_VERSION_CURRENT);
  370. return -EINVAL;
  371. }
  372. dev_info(dev, "selected api version: %u (requested %u)\n",
  373. api_version, TRUSTY_API_VERSION_CURRENT);
  374. s->api_version = api_version;
  375. return 0;
  376. }
  377. static int trusty_probe(struct platform_device *pdev)
  378. {
  379. int ret;
  380. struct trusty_state *s;
  381. struct device_node *node = pdev->dev.of_node;
  382. if (!node) {
  383. dev_err(&pdev->dev, "of_node required\n");
  384. return -EINVAL;
  385. }
  386. s = kzalloc(sizeof(*s), GFP_KERNEL);
  387. if (!s) {
  388. ret = -ENOMEM;
  389. goto err_allocate_state;
  390. }
  391. mutex_init(&s->smc_lock);
  392. ATOMIC_INIT_NOTIFIER_HEAD(&s->notifier);
  393. init_completion(&s->cpu_idle_completion);
  394. platform_set_drvdata(pdev, s);
  395. trusty_init_version(s, &pdev->dev);
  396. ret = trusty_init_api_version(s, &pdev->dev);
  397. if (ret < 0)
  398. goto err_api_version;
  399. ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
  400. if (ret < 0) {
  401. dev_err(&pdev->dev, "Failed to add children: %d\n", ret);
  402. goto err_add_children;
  403. }
  404. #ifdef CONFIG_MT_TRUSTY_DEBUGFS
  405. trusty_create_debugfs(s, &pdev->dev);
  406. #endif
  407. return 0;
  408. err_add_children:
  409. err_api_version:
  410. if (s->version_str) {
  411. device_remove_file(&pdev->dev, &dev_attr_trusty_version);
  412. kfree(s->version_str);
  413. }
  414. device_for_each_child(&pdev->dev, NULL, trusty_remove_child);
  415. mutex_destroy(&s->smc_lock);
  416. kfree(s);
  417. err_allocate_state:
  418. return ret;
  419. }
  420. static int trusty_remove(struct platform_device *pdev)
  421. {
  422. struct trusty_state *s = platform_get_drvdata(pdev);
  423. device_for_each_child(&pdev->dev, NULL, trusty_remove_child);
  424. mutex_destroy(&s->smc_lock);
  425. if (s->version_str) {
  426. device_remove_file(&pdev->dev, &dev_attr_trusty_version);
  427. kfree(s->version_str);
  428. }
  429. kfree(s);
  430. return 0;
  431. }
  432. static const struct of_device_id trusty_of_match[] = {
  433. { .compatible = "android,trusty-smc-v1", },
  434. {},
  435. };
  436. static struct platform_driver trusty_driver = {
  437. .probe = trusty_probe,
  438. .remove = trusty_remove,
  439. .driver = {
  440. .name = "trusty",
  441. .owner = THIS_MODULE,
  442. .of_match_table = trusty_of_match,
  443. },
  444. };
  445. static int __init trusty_driver_init(void)
  446. {
  447. return platform_driver_register(&trusty_driver);
  448. }
  449. static void __exit trusty_driver_exit(void)
  450. {
  451. platform_driver_unregister(&trusty_driver);
  452. }
  453. subsys_initcall(trusty_driver_init);
  454. module_exit(trusty_driver_exit);