main.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /*
  2. * @file hdm.c
  3. * @brief HDM Support
  4. * Copyright (c) 2020, Samsung Electronics Corporation. All rights reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 and
  8. * only version 2 as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <linux/kernel.h>
  16. #include <linux/device.h>
  17. #include <linux/module.h>
  18. #include <linux/proc_fs.h>
  19. #include <linux/mm.h>
  20. #if defined(CONFIG_ARCH_QCOM)
  21. #include <linux/of.h>
  22. #include <linux/of_address.h>
  23. #include <linux/resource.h>
  24. #endif
  25. #include <linux/hdm.h>
  26. #include <linux/fs.h>
  27. #include <linux/debugfs.h>
  28. #include <linux/uaccess.h>
  29. #include <linux/sec_class.h>
  30. #if defined(CONFIG_ARCH_QCOM)
  31. #include <linux/sched/signal.h>
  32. #include <soc/qcom/secure_buffer.h>
  33. #include <linux/qtee_shmbridge.h>
  34. #include <linux/scatterlist.h>
  35. #endif
  36. #include "hdm_log.h"
  37. #include "uh.h"
  38. int hdm_log_level = HDM_LOG_LEVEL;
  39. static int is_hdm_initialized;
  40. static u64 supported_subsystem = 0;
  41. static char *status = "NONE";
  42. module_param(status, charp, 0444);
  43. MODULE_PARM_DESC(status, "HDM status");
  44. int hdm_wifi_support = 0;
  45. static int hdm_cp_support = 0;
  46. EXPORT_SYMBOL(hdm_wifi_support);
  47. int hdm_is_wlan_enabled(void)
  48. {
  49. return hdm_wifi_support;
  50. }
  51. EXPORT_SYMBOL(hdm_is_wlan_enabled);
  52. int hdm_is_cp_enabled(void)
  53. {
  54. return hdm_cp_support;
  55. }
  56. EXPORT_SYMBOL(hdm_is_cp_enabled);
  57. void hdm_printk(int level, const char *fmt, ...)
  58. {
  59. struct va_format vaf;
  60. va_list args;
  61. if (hdm_log_level < level)
  62. return;
  63. va_start(args, fmt);
  64. vaf.fmt = fmt;
  65. vaf.va = &args;
  66. printk(KERN_INFO "%s %pV", TAG, &vaf);
  67. va_end(args);
  68. }
  69. static int __init hdm_flag_setup(void)
  70. {
  71. char tmp_hdm_status[100] = {0};
  72. char *tmp_p = NULL;
  73. char *token = NULL;
  74. int cnt = 0;
  75. long val = 0;
  76. int err = 0;
  77. hdm_wifi_support = 0;
  78. hdm_cp_support = 0;
  79. hdm_info("%s hdm.status = %s\n", __func__, status);
  80. if (status) {
  81. snprintf(tmp_hdm_status, sizeof(tmp_hdm_status), "%s", status);
  82. tmp_p = tmp_hdm_status;
  83. token = strsep(&tmp_p, "&|");
  84. while (token) {
  85. //even = hdm applied bit
  86. if (cnt++%2) {
  87. err = kstrtol(token, 16, &val);
  88. if (err)
  89. return err;
  90. if (val & HDM_WIFI_SUPPORT_BIT && hdm_wifi_support == 0) {
  91. hdm_info("%s wifi bit set\n", __func__);
  92. hdm_wifi_support = 1;
  93. }
  94. if (val & HDM_CP_SUPPORT_BIT && hdm_cp_support == 0) {
  95. hdm_info("%s cp bit set\n", __func__);
  96. hdm_cp_support = 1;
  97. }
  98. }
  99. token = strsep(&tmp_p, "&|");
  100. }
  101. }
  102. hdm_info("%s hdm_wifi_support = %d, hdm_cp_support = %d\n", __func__, hdm_wifi_support, hdm_cp_support);
  103. return 0;
  104. }
  105. static ssize_t hdm_policy_store(struct device *dev,
  106. struct device_attribute *attr,
  107. const char *buf, size_t count)
  108. {
  109. unsigned long mode = HDM_CMD_MAX;
  110. int c, p;
  111. if (count == 0) {
  112. hdm_err("%s count = 0\n", __func__);
  113. goto error;
  114. }
  115. if (kstrtoul(buf, 0, &mode)) {
  116. goto error;
  117. };
  118. if (mode > HDM_CMD_MAX) {
  119. hdm_err("%s command size max fail. %d\n", __func__, mode);
  120. goto error;
  121. }
  122. hdm_info("%s: command id: 0x%x\n", __func__, (int)mode);
  123. c = (int)(mode & HDM_C_BITMASK);
  124. p = (int)(mode & HDM_P_BITMASK);
  125. hdm_info("%s m:0x%x c:0x%x p:0x%x\n", __func__, (int)mode, c, p);
  126. switch (c) {
  127. case HDM_FLAG_SET:
  128. hdm_info("%s HDM_FLAG_SET\n", __func__);
  129. if ((p & HDM_WIFI_SUPPORT_BIT) == HDM_WIFI_SUPPORT_BIT) {
  130. hdm_info("%s wifi bit set\n", __func__);
  131. hdm_wifi_support = 1;
  132. }
  133. break;
  134. case HDM_FLAG_UNSET:
  135. hdm_info("%s HDM_FLAG_UNSET\n", __func__);
  136. if ((p & HDM_WIFI_SUPPORT_BIT) == HDM_WIFI_SUPPORT_BIT) {
  137. hdm_info("%s wifi bit unset\n", __func__);
  138. hdm_wifi_support = 0;
  139. }
  140. break;
  141. #if defined(CONFIG_ARCH_QCOM)
  142. case HDM_HYP_CALL:
  143. hdm_info("%s HDM_HYP_CALL\n", __func__);
  144. uh_call(UH_APP_HDM, 9, 0, p, 0, 0);
  145. break;
  146. case HDM_HYP_CALLP:
  147. hdm_info("%s HDM_HYP_CALLP\n", __func__);
  148. uh_call(UH_APP_HDM, 2, 0, p, 0, 0);
  149. break;
  150. case HDM_HYP_INIT:
  151. hdm_info("%s HDM_HYP_INIT\n", __func__);
  152. uh_call(UH_APP_HDM, 3, 0, 0, 0, 0);
  153. break;
  154. case HDM_HYP_CLEAR:
  155. hdm_info("%s HDM_HYP_CLEAR\n", __func__);
  156. uh_call(UH_APP_HDM, 4, 0, 0, 0, 0);
  157. break;
  158. #endif
  159. default:
  160. goto error;
  161. }
  162. error:
  163. return count;
  164. }
  165. static void get_supported_subsystem(void)
  166. {
  167. if (is_hdm_initialized != true) {
  168. uh_call(UH_APP_HDM, HDM_GET_SUPPORTED_SUBSYSTEM, (u64)&supported_subsystem, 0, 0, 0);
  169. hdm_info("supported_subsystem = %012llx\n", supported_subsystem);
  170. is_hdm_initialized = true;
  171. }
  172. }
  173. static ssize_t hdm_subsystem_show(struct device *dev,
  174. struct device_attribute *attr, char *buf)
  175. {
  176. u32 hdm_version = 0;
  177. hdm_info("%s\n", __func__);
  178. get_supported_subsystem();
  179. hdm_version = (supported_subsystem >> 12) & 0xFFF;
  180. hdm_info("hdm_version = %03x\n", hdm_version);
  181. return snprintf(buf, 7, "0x%03x\n", hdm_version);
  182. }
  183. static ssize_t pad_subsystem_show(struct device *dev,
  184. struct device_attribute *attr, char *buf)
  185. {
  186. u32 pad_version = 0;
  187. hdm_info("%s\n", __func__);
  188. get_supported_subsystem();
  189. pad_version = supported_subsystem & 0xFFF;
  190. hdm_info("pad_version = %03x\n", pad_version);
  191. return snprintf(buf, 7, "0x%03x\n", pad_version);
  192. }
  193. static ssize_t bt_block_sub_show(struct device *dev,
  194. struct device_attribute *attr, char *buf)
  195. {
  196. u32 bt_block_sub = 0;
  197. hdm_info("%s\n", __func__);
  198. get_supported_subsystem();
  199. bt_block_sub = (supported_subsystem >> 24) & 0xFFF;
  200. hdm_info("bt_block_sub = %03x\n", bt_block_sub);
  201. return snprintf(buf, 7, "0x%03x\n", bt_block_sub);
  202. }
  203. static ssize_t bt_unblock_sub_show(struct device *dev,
  204. struct device_attribute *attr, char *buf)
  205. {
  206. u32 bt_unblock_sub = 0;
  207. hdm_info("%s\n", __func__);
  208. get_supported_subsystem();
  209. bt_unblock_sub = (supported_subsystem >> 36) & 0xFFF;
  210. hdm_info("bt_unblock_sub = %03x\n", bt_unblock_sub);
  211. return snprintf(buf, 7, "0x%03x\n", bt_unblock_sub);
  212. }
  213. static DEVICE_ATTR_WO(hdm_policy);
  214. static DEVICE_ATTR_RO(hdm_subsystem);
  215. static DEVICE_ATTR_RO(pad_subsystem);
  216. static DEVICE_ATTR_RO(bt_block_sub);
  217. static DEVICE_ATTR_RO(bt_unblock_sub);
  218. #if defined(CONFIG_ARCH_QCOM)
  219. int hyp_assign_phys(phys_addr_t addr, u64 size, u32 *source_vm_list,
  220. int source_nelems, int *dest_vmids,
  221. int *dest_perms, int dest_nelems)
  222. {
  223. struct sg_table table;
  224. int ret;
  225. ret = sg_alloc_table(&table, 1, GFP_KERNEL);
  226. if (ret)
  227. return ret;
  228. sg_set_page(table.sgl, phys_to_page(addr), size, 0);
  229. ret = hyp_assign_table(&table, source_vm_list, source_nelems,
  230. dest_vmids, dest_perms, dest_nelems);
  231. sg_free_table(&table);
  232. return ret;
  233. }
  234. static uint64_t qseelog_shmbridge_handle;
  235. static int __init __hdm_init_of(void)
  236. {
  237. struct device_node *node;
  238. struct resource r;
  239. int ret;
  240. phys_addr_t addr;
  241. u64 size;
  242. uint32_t ns_vmids[] = {VMID_HLOS_FREE};
  243. uint32_t ns_vm_perms[] = {PERM_READ | PERM_WRITE};
  244. uint32_t ns_vm_nums = 1;
  245. int src_vmids[1] = {VMID_HLOS};
  246. int dest_vmids[1] = {VMID_HLOS_FREE};
  247. int dest_perms[1] = {PERM_READ | PERM_WRITE};
  248. hdm_info("%s start\n", __func__);
  249. node = of_find_node_by_name(NULL, "samsung,sec_hdm");
  250. if (!node) {
  251. hdm_err("failed of_find_node_by_name\n");
  252. return -ENODEV;
  253. }
  254. node = of_parse_phandle(node, "memory-region", 0);
  255. if (!node) {
  256. hdm_err("no memory-region specified\n");
  257. return -EINVAL;
  258. }
  259. ret = of_address_to_resource(node, 0, &r);
  260. if (ret) {
  261. hdm_err("failed of_address_to_resource\n");
  262. return ret;
  263. }
  264. addr = r.start;
  265. size = resource_size(&r);
  266. ret = hyp_assign_phys(addr, size, src_vmids, 1, dest_vmids, dest_perms, 1);
  267. if (ret) {
  268. hdm_err("%s: failed for %pa address of size %zx rc:%d\n",
  269. __func__, &addr, size, ret);
  270. }
  271. ret = qtee_shmbridge_register(addr, size, ns_vmids, ns_vm_perms,
  272. ns_vm_nums, PERM_READ | PERM_WRITE, &qseelog_shmbridge_handle);
  273. if (ret)
  274. hdm_err("failed to create bridge for qsee_log buffer\n");
  275. hdm_info("%s done\n", __func__);
  276. return 0;
  277. }
  278. #endif
  279. static int __init hdm_test_init(void)
  280. {
  281. struct device *dev;
  282. #if defined(CONFIG_ARCH_QCOM)
  283. int err;
  284. #endif
  285. hdm_flag_setup();
  286. dev = sec_device_create(NULL, "hdm");
  287. WARN_ON(!dev);
  288. if (IS_ERR(dev)) {
  289. hdm_err("%s Failed to create devce\n", __func__);
  290. return 0;
  291. }
  292. if (device_create_file(dev, &dev_attr_hdm_policy) < 0) {
  293. hdm_err("%s Failed to create device file\n", __func__);
  294. return 0;
  295. }
  296. if (device_create_file(dev, &dev_attr_hdm_subsystem) < 0) {
  297. hdm_err("%s Failed to create device file\n", __func__);
  298. return 0;
  299. }
  300. if (device_create_file(dev, &dev_attr_pad_subsystem) < 0) {
  301. hdm_err("%s Failed to create device file\n", __func__);
  302. return 0;
  303. }
  304. if (device_create_file(dev, &dev_attr_bt_block_sub) < 0) {
  305. hdm_err("%s Failed to create device file\n", __func__);
  306. return 0;
  307. }
  308. if (device_create_file(dev, &dev_attr_bt_unblock_sub) < 0) {
  309. hdm_err("%s Failed to create device file\n", __func__);
  310. return 0;
  311. }
  312. #if defined(CONFIG_ARCH_QCOM)
  313. err = __hdm_init_of();
  314. if (err)
  315. return err;
  316. #endif
  317. hdm_info("%s end\n", __func__);
  318. return 0;
  319. }
  320. module_init(hdm_test_init);
  321. MODULE_AUTHOR("Taeho Kim <[email protected]>");
  322. MODULE_AUTHOR("Shinjae Lee <[email protected]>");
  323. MODULE_DESCRIPTION("HDM driver");
  324. MODULE_LICENSE("GPL");