cpaccess.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /* Copyright (c) 2010-2014, The Linux Foundation. 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. #include <linux/module.h>
  13. #include <linux/init.h>
  14. #include <linux/sched.h>
  15. #include <linux/sysrq.h>
  16. #include <linux/time.h>
  17. #include <linux/proc_fs.h>
  18. #include <linux/kernel_stat.h>
  19. #include <linux/uaccess.h>
  20. #include <linux/sysdev.h>
  21. #include <linux/delay.h>
  22. #include <linux/device.h>
  23. #include <linux/kernel.h>
  24. #include <linux/spinlock.h>
  25. #include <linux/semaphore.h>
  26. #include <linux/file.h>
  27. #include <linux/percpu.h>
  28. #include <linux/string.h>
  29. #include <linux/smp.h>
  30. #include <asm/cacheflush.h>
  31. #include <asm/smp_plat.h>
  32. #include <asm/mmu_writeable.h>
  33. #ifdef CONFIG_ARCH_MSM_KRAIT
  34. #include <mach/msm-krait-l2-accessors.h>
  35. #endif
  36. #define TYPE_MAX_CHARACTERS 10
  37. /*
  38. * CP parameters
  39. */
  40. struct cp_params {
  41. unsigned long il2index;
  42. unsigned long cp;
  43. unsigned long op1;
  44. unsigned long op2;
  45. unsigned long crn;
  46. unsigned long crm;
  47. unsigned long write_value;
  48. char rw;
  49. };
  50. static struct semaphore cp_sem;
  51. static unsigned long il2_output;
  52. static int cpu;
  53. char type[TYPE_MAX_CHARACTERS] = "C";
  54. static DEFINE_PER_CPU(struct cp_params, cp_param)
  55. = { 0, 15, 0, 0, 0, 0, 0, 'r' };
  56. static struct sysdev_class cpaccess_sysclass = {
  57. .name = "cpaccess",
  58. };
  59. void cpaccess_dummy_inst(void);
  60. #ifdef CONFIG_ARCH_MSM_KRAIT
  61. /*
  62. * do_read_il2 - Read indirect L2 registers
  63. * @ret: Pointer to return value
  64. *
  65. */
  66. static void do_read_il2(void *ret)
  67. {
  68. *(unsigned long *)ret =
  69. get_l2_indirect_reg(per_cpu(cp_param.il2index, cpu));
  70. }
  71. /*
  72. * do_write_il2 - Write indirect L2 registers
  73. * @ret: Pointer to return value
  74. *
  75. */
  76. static void do_write_il2(void *ret)
  77. {
  78. set_l2_indirect_reg(per_cpu(cp_param.il2index, cpu),
  79. per_cpu(cp_param.write_value, cpu));
  80. *(unsigned long *)ret =
  81. get_l2_indirect_reg(per_cpu(cp_param.il2index, cpu));
  82. }
  83. /*
  84. * do_il2_rw - Call Read/Write indirect L2 register functions
  85. * @ret: Pointer to return value in case of CP register
  86. *
  87. */
  88. static int do_il2_rw(char *str_tmp)
  89. {
  90. unsigned long write_value, il2index;
  91. char rw;
  92. int ret = 0;
  93. il2index = 0;
  94. sscanf(str_tmp, "%lx:%c:%lx:%d", &il2index, &rw, &write_value,
  95. &cpu);
  96. per_cpu(cp_param.il2index, cpu) = il2index;
  97. per_cpu(cp_param.rw, cpu) = rw;
  98. per_cpu(cp_param.write_value, cpu) = write_value;
  99. if (per_cpu(cp_param.rw, cpu) == 'r') {
  100. if (is_smp()) {
  101. if (smp_call_function_single(cpu, do_read_il2,
  102. &il2_output, 1))
  103. pr_err("Error cpaccess smp call single\n");
  104. } else
  105. do_read_il2(&il2_output);
  106. } else if (per_cpu(cp_param.rw, cpu) == 'w') {
  107. if (is_smp()) {
  108. if (smp_call_function_single(cpu, do_write_il2,
  109. &il2_output, 1))
  110. pr_err("Error cpaccess smp call single\n");
  111. } else
  112. do_write_il2(&il2_output);
  113. } else {
  114. pr_err("cpaccess: Wrong Entry for 'r' or 'w'.\n");
  115. return -EINVAL;
  116. }
  117. return ret;
  118. }
  119. #else
  120. static void do_il2_rw(char *str_tmp)
  121. {
  122. il2_output = 0;
  123. }
  124. #endif
  125. /*
  126. * get_asm_value - Dummy fuction
  127. * @write_val: Write value incase of a CP register write operation.
  128. *
  129. * This function is just a placeholder. The first 2 instructions
  130. * will be inserted to perform MRC/MCR instruction and a return.
  131. * See do_cpregister_rw function. Value passed to function is
  132. * accessed from r0 register.
  133. */
  134. static noinline unsigned long cpaccess_dummy(unsigned long write_val)
  135. {
  136. unsigned long ret = 0xBEEF;
  137. asm volatile (".globl cpaccess_dummy_inst\n"
  138. "cpaccess_dummy_inst:\n\t"
  139. "mrc p15, 0, %0, c0, c0, 0\n\t" : "=r" (ret) :
  140. "r" (write_val));
  141. return ret;
  142. } __attribute__((aligned(32)))
  143. /*
  144. * get_asm_value - Read/Write CP registers
  145. * @ret: Pointer to return value in case of CP register
  146. * read op.
  147. *
  148. */
  149. static void get_asm_value(void *ret)
  150. {
  151. *(unsigned long *)ret =
  152. cpaccess_dummy(per_cpu(cp_param.write_value, cpu));
  153. }
  154. /*
  155. * dp_cpregister_rw - Read/Write CP registers
  156. * @write: 1 for Write and 0 for Read operation
  157. *
  158. * Returns value read from CP register
  159. */
  160. static unsigned long do_cpregister_rw(int write)
  161. {
  162. unsigned long opcode, ret, *p_opcode;
  163. /*
  164. * Mask the crn, crm, op1, op2 and cp values so they do not
  165. * interfer with other fields of the op code.
  166. */
  167. per_cpu(cp_param.cp, cpu) &= 0xF;
  168. per_cpu(cp_param.crn, cpu) &= 0xF;
  169. per_cpu(cp_param.crm, cpu) &= 0xF;
  170. per_cpu(cp_param.op1, cpu) &= 0x7;
  171. per_cpu(cp_param.op2, cpu) &= 0x7;
  172. /*
  173. * Base MRC opcode for MIDR is EE100010,
  174. * MCR is 0xEE000010
  175. */
  176. opcode = (write == 1 ? 0xEE000010 : 0xEE100010);
  177. opcode |= (per_cpu(cp_param.crn, cpu)<<16) |
  178. (per_cpu(cp_param.crm, cpu)<<0) |
  179. (per_cpu(cp_param.op1, cpu)<<21) |
  180. (per_cpu(cp_param.op2, cpu)<<5) |
  181. (per_cpu(cp_param.cp, cpu) << 8);
  182. /*
  183. * Grab address of the Dummy function, write the MRC/MCR
  184. * instruction, ensuring cache coherency.
  185. */
  186. p_opcode = (unsigned long *)&cpaccess_dummy_inst;
  187. mem_text_write_kernel_word(p_opcode, opcode);
  188. #ifdef CONFIG_SMP
  189. /*
  190. * Use smp_call_function_single to do CPU core specific
  191. * get_asm_value function call.
  192. */
  193. if (smp_call_function_single(cpu, get_asm_value, &ret, 1))
  194. printk(KERN_ERR "Error cpaccess smp call single\n");
  195. #else
  196. get_asm_value(&ret);
  197. #endif
  198. return ret;
  199. }
  200. static int get_register_params(char *str_tmp)
  201. {
  202. unsigned long op1, op2, crn, crm, cp = 15, write_value, il2index;
  203. char rw;
  204. int cnt = 0;
  205. il2index = 0;
  206. strncpy(type, strsep(&str_tmp, ":"), TYPE_MAX_CHARACTERS);
  207. if (strncasecmp(type, "C", TYPE_MAX_CHARACTERS) == 0) {
  208. sscanf(str_tmp, "%lu:%lu:%lu:%lu:%lu:%c:%lx:%d",
  209. &cp, &op1, &crn, &crm, &op2, &rw, &write_value, &cpu);
  210. per_cpu(cp_param.cp, cpu) = cp;
  211. per_cpu(cp_param.op1, cpu) = op1;
  212. per_cpu(cp_param.crn, cpu) = crn;
  213. per_cpu(cp_param.crm, cpu) = crm;
  214. per_cpu(cp_param.op2, cpu) = op2;
  215. per_cpu(cp_param.rw, cpu) = rw;
  216. per_cpu(cp_param.write_value, cpu) = write_value;
  217. if ((per_cpu(cp_param.rw, cpu) != 'w') &&
  218. (per_cpu(cp_param.rw, cpu) != 'r')) {
  219. pr_err("cpaccess: Wrong entry for 'r' or 'w'.\n");
  220. return -EINVAL;
  221. }
  222. if (per_cpu(cp_param.rw, cpu) == 'w')
  223. do_cpregister_rw(1);
  224. } else if (strncasecmp(type, "IL2", TYPE_MAX_CHARACTERS) == 0)
  225. do_il2_rw(str_tmp);
  226. else {
  227. pr_err("cpaccess: Not a valid type. Entered: %s\n", type);
  228. return -EINVAL;
  229. }
  230. return cnt;
  231. }
  232. /*
  233. * cp_register_write_sysfs - sysfs interface for writing to
  234. * CP register
  235. */
  236. static ssize_t cp_register_write_sysfs(
  237. struct kobject *kobj, struct kobj_attribute *attr,
  238. const char *buf, size_t cnt)
  239. {
  240. char *str_tmp = (char *)buf;
  241. if (down_timeout(&cp_sem, 6000))
  242. return -ERESTARTSYS;
  243. get_register_params(str_tmp);
  244. return cnt;
  245. }
  246. /*
  247. * wrapper for deprecated sysdev write interface
  248. */
  249. static ssize_t sysdev_cp_register_write_sysfs(struct sys_device *dev,
  250. struct sysdev_attribute *attr, const char *buf, size_t cnt)
  251. {
  252. return cp_register_write_sysfs(NULL, NULL, buf, cnt);
  253. }
  254. /*
  255. * cp_register_read_sysfs - sysfs interface for reading CP registers
  256. *
  257. * Code to read in the CPxx crn, crm, op1, op2 variables, or into
  258. * the base MRC opcode, store to executable memory, clean/invalidate
  259. * caches and then execute the new instruction and provide the
  260. * result to the caller.
  261. */
  262. static ssize_t cp_register_read_sysfs(
  263. struct kobject *kobj, struct kobj_attribute *attr, char *buf)
  264. {
  265. int ret;
  266. if (strncasecmp(type, "C", TYPE_MAX_CHARACTERS) == 0)
  267. ret = snprintf(buf, TYPE_MAX_CHARACTERS, "%lx\n",
  268. do_cpregister_rw(0));
  269. else if (strncasecmp(type, "IL2", TYPE_MAX_CHARACTERS) == 0)
  270. ret = snprintf(buf, TYPE_MAX_CHARACTERS, "%lx\n", il2_output);
  271. else
  272. ret = -EINVAL;
  273. if (cp_sem.count <= 0)
  274. up(&cp_sem);
  275. return ret;
  276. }
  277. /*
  278. * wrapper for deprecated sysdev read interface
  279. */
  280. static ssize_t sysdev_cp_register_read_sysfs(struct sys_device *dev,
  281. struct sysdev_attribute *attr, char *buf)
  282. {
  283. return cp_register_read_sysfs(NULL, NULL, buf);
  284. }
  285. /*
  286. * Setup sysfs files
  287. */
  288. SYSDEV_ATTR(cp_rw, 0644, sysdev_cp_register_read_sysfs,
  289. sysdev_cp_register_write_sysfs);
  290. static struct sys_device device_cpaccess = {
  291. .id = 0,
  292. .cls = &cpaccess_sysclass,
  293. };
  294. static struct device cpaccess_dev = {
  295. .init_name = "cpaccess",
  296. };
  297. static struct kobj_attribute cp_rw_attribute =
  298. __ATTR(cp_rw, 0644, cp_register_read_sysfs, cp_register_write_sysfs);
  299. static struct attribute *attrs[] = {
  300. &cp_rw_attribute.attr,
  301. NULL,
  302. };
  303. static struct attribute_group attr_group = {
  304. .name = "cpaccess0",
  305. .attrs = attrs,
  306. };
  307. /*
  308. * init_cpaccess_sysfs - initialize sys devices
  309. */
  310. static int __init init_cpaccess_sysfs(void)
  311. {
  312. /*
  313. * sysdev interface is deprecated and will be removed
  314. * after migration to new sysfs entry
  315. */
  316. int error = sysdev_class_register(&cpaccess_sysclass);
  317. if (!error)
  318. error = sysdev_register(&device_cpaccess);
  319. else
  320. pr_err("Error initializing cpaccess interface\n");
  321. if (!error)
  322. error = sysdev_create_file(&device_cpaccess,
  323. &attr_cp_rw);
  324. else {
  325. pr_err("Error initializing cpaccess interface\n");
  326. goto exit0;
  327. }
  328. error = device_register(&cpaccess_dev);
  329. if (error) {
  330. pr_err("Error registering cpaccess device\n");
  331. goto exit0;
  332. }
  333. error = sysfs_create_group(&cpaccess_dev.kobj, &attr_group);
  334. if (error) {
  335. pr_err("Error creating cpaccess sysfs group\n");
  336. goto exit1;
  337. }
  338. sema_init(&cp_sem, 1);
  339. /*
  340. * Make the target instruction writeable when built as a module
  341. */
  342. set_memory_rw((unsigned long)&cpaccess_dummy_inst & PAGE_MASK, 1);
  343. return 0;
  344. exit1:
  345. device_unregister(&cpaccess_dev);
  346. exit0:
  347. sysdev_unregister(&device_cpaccess);
  348. sysdev_class_unregister(&cpaccess_sysclass);
  349. return error;
  350. }
  351. static void __exit exit_cpaccess_sysfs(void)
  352. {
  353. sysdev_remove_file(&device_cpaccess, &attr_cp_rw);
  354. sysdev_unregister(&device_cpaccess);
  355. sysdev_class_unregister(&cpaccess_sysclass);
  356. sysfs_remove_group(&cpaccess_dev.kobj, &attr_group);
  357. device_unregister(&cpaccess_dev);
  358. }
  359. module_init(init_cpaccess_sysfs);
  360. module_exit(exit_cpaccess_sysfs);
  361. MODULE_LICENSE("GPL v2");