uaccess.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Standard user space access functions based on mvcp/mvcs and doing
  4. * interesting things in the secondary space mode.
  5. *
  6. * Copyright IBM Corp. 2006,2014
  7. * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  8. * Gerald Schaefer (gerald.schaefer@de.ibm.com)
  9. */
  10. #include <linux/jump_label.h>
  11. #include <linux/uaccess.h>
  12. #include <linux/export.h>
  13. #include <linux/errno.h>
  14. #include <linux/mm.h>
  15. #include <asm/mmu_context.h>
  16. #include <asm/facility.h>
  17. #ifndef CONFIG_HAVE_MARCH_Z10_FEATURES
  18. static DEFINE_STATIC_KEY_FALSE(have_mvcos);
  19. static int __init uaccess_init(void)
  20. {
  21. if (test_facility(27))
  22. static_branch_enable(&have_mvcos);
  23. return 0;
  24. }
  25. early_initcall(uaccess_init);
  26. static inline int copy_with_mvcos(void)
  27. {
  28. if (static_branch_likely(&have_mvcos))
  29. return 1;
  30. return 0;
  31. }
  32. #else
  33. static inline int copy_with_mvcos(void)
  34. {
  35. return 1;
  36. }
  37. #endif
  38. void set_fs(mm_segment_t fs)
  39. {
  40. current->thread.mm_segment = fs;
  41. if (fs == USER_DS) {
  42. __ctl_load(S390_lowcore.user_asce, 1, 1);
  43. clear_cpu_flag(CIF_ASCE_PRIMARY);
  44. } else {
  45. __ctl_load(S390_lowcore.kernel_asce, 1, 1);
  46. set_cpu_flag(CIF_ASCE_PRIMARY);
  47. }
  48. if (fs & 1) {
  49. if (fs == USER_DS_SACF)
  50. __ctl_load(S390_lowcore.user_asce, 7, 7);
  51. else
  52. __ctl_load(S390_lowcore.kernel_asce, 7, 7);
  53. set_cpu_flag(CIF_ASCE_SECONDARY);
  54. }
  55. }
  56. EXPORT_SYMBOL(set_fs);
  57. mm_segment_t enable_sacf_uaccess(void)
  58. {
  59. mm_segment_t old_fs;
  60. unsigned long asce, cr;
  61. unsigned long flags;
  62. old_fs = current->thread.mm_segment;
  63. if (old_fs & 1)
  64. return old_fs;
  65. /* protect against a concurrent page table upgrade */
  66. local_irq_save(flags);
  67. current->thread.mm_segment |= 1;
  68. asce = S390_lowcore.kernel_asce;
  69. if (likely(old_fs == USER_DS)) {
  70. __ctl_store(cr, 1, 1);
  71. if (cr != S390_lowcore.kernel_asce) {
  72. __ctl_load(S390_lowcore.kernel_asce, 1, 1);
  73. set_cpu_flag(CIF_ASCE_PRIMARY);
  74. }
  75. asce = S390_lowcore.user_asce;
  76. }
  77. __ctl_store(cr, 7, 7);
  78. if (cr != asce) {
  79. __ctl_load(asce, 7, 7);
  80. set_cpu_flag(CIF_ASCE_SECONDARY);
  81. }
  82. local_irq_restore(flags);
  83. return old_fs;
  84. }
  85. EXPORT_SYMBOL(enable_sacf_uaccess);
  86. void disable_sacf_uaccess(mm_segment_t old_fs)
  87. {
  88. current->thread.mm_segment = old_fs;
  89. if (old_fs == USER_DS && test_facility(27)) {
  90. __ctl_load(S390_lowcore.user_asce, 1, 1);
  91. clear_cpu_flag(CIF_ASCE_PRIMARY);
  92. }
  93. }
  94. EXPORT_SYMBOL(disable_sacf_uaccess);
  95. static inline unsigned long copy_from_user_mvcos(void *x, const void __user *ptr,
  96. unsigned long size)
  97. {
  98. register unsigned long reg0 asm("0") = 0x01UL;
  99. unsigned long tmp1, tmp2;
  100. tmp1 = -4096UL;
  101. asm volatile(
  102. "0: .insn ss,0xc80000000000,0(%0,%2),0(%1),0\n"
  103. "6: jz 4f\n"
  104. "1: algr %0,%3\n"
  105. " slgr %1,%3\n"
  106. " slgr %2,%3\n"
  107. " j 0b\n"
  108. "2: la %4,4095(%1)\n"/* %4 = ptr + 4095 */
  109. " nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */
  110. " slgr %4,%1\n"
  111. " clgr %0,%4\n" /* copy crosses next page boundary? */
  112. " jnh 5f\n"
  113. "3: .insn ss,0xc80000000000,0(%4,%2),0(%1),0\n"
  114. "7: slgr %0,%4\n"
  115. " j 5f\n"
  116. "4: slgr %0,%0\n"
  117. "5:\n"
  118. EX_TABLE(0b,2b) EX_TABLE(3b,5b) EX_TABLE(6b,2b) EX_TABLE(7b,5b)
  119. : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
  120. : "d" (reg0) : "cc", "memory");
  121. return size;
  122. }
  123. static inline unsigned long copy_from_user_mvcp(void *x, const void __user *ptr,
  124. unsigned long size)
  125. {
  126. unsigned long tmp1, tmp2;
  127. mm_segment_t old_fs;
  128. old_fs = enable_sacf_uaccess();
  129. tmp1 = -256UL;
  130. asm volatile(
  131. " sacf 0\n"
  132. "0: mvcp 0(%0,%2),0(%1),%3\n"
  133. "7: jz 5f\n"
  134. "1: algr %0,%3\n"
  135. " la %1,256(%1)\n"
  136. " la %2,256(%2)\n"
  137. "2: mvcp 0(%0,%2),0(%1),%3\n"
  138. "8: jnz 1b\n"
  139. " j 5f\n"
  140. "3: la %4,255(%1)\n" /* %4 = ptr + 255 */
  141. " lghi %3,-4096\n"
  142. " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */
  143. " slgr %4,%1\n"
  144. " clgr %0,%4\n" /* copy crosses next page boundary? */
  145. " jnh 6f\n"
  146. "4: mvcp 0(%4,%2),0(%1),%3\n"
  147. "9: slgr %0,%4\n"
  148. " j 6f\n"
  149. "5: slgr %0,%0\n"
  150. "6: sacf 768\n"
  151. EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b)
  152. EX_TABLE(7b,3b) EX_TABLE(8b,3b) EX_TABLE(9b,6b)
  153. : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
  154. : : "cc", "memory");
  155. disable_sacf_uaccess(old_fs);
  156. return size;
  157. }
  158. unsigned long raw_copy_from_user(void *to, const void __user *from, unsigned long n)
  159. {
  160. if (copy_with_mvcos())
  161. return copy_from_user_mvcos(to, from, n);
  162. return copy_from_user_mvcp(to, from, n);
  163. }
  164. EXPORT_SYMBOL(raw_copy_from_user);
  165. static inline unsigned long copy_to_user_mvcos(void __user *ptr, const void *x,
  166. unsigned long size)
  167. {
  168. register unsigned long reg0 asm("0") = 0x010000UL;
  169. unsigned long tmp1, tmp2;
  170. tmp1 = -4096UL;
  171. asm volatile(
  172. "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
  173. "6: jz 4f\n"
  174. "1: algr %0,%3\n"
  175. " slgr %1,%3\n"
  176. " slgr %2,%3\n"
  177. " j 0b\n"
  178. "2: la %4,4095(%1)\n"/* %4 = ptr + 4095 */
  179. " nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */
  180. " slgr %4,%1\n"
  181. " clgr %0,%4\n" /* copy crosses next page boundary? */
  182. " jnh 5f\n"
  183. "3: .insn ss,0xc80000000000,0(%4,%1),0(%2),0\n"
  184. "7: slgr %0,%4\n"
  185. " j 5f\n"
  186. "4: slgr %0,%0\n"
  187. "5:\n"
  188. EX_TABLE(0b,2b) EX_TABLE(3b,5b) EX_TABLE(6b,2b) EX_TABLE(7b,5b)
  189. : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
  190. : "d" (reg0) : "cc", "memory");
  191. return size;
  192. }
  193. static inline unsigned long copy_to_user_mvcs(void __user *ptr, const void *x,
  194. unsigned long size)
  195. {
  196. unsigned long tmp1, tmp2;
  197. mm_segment_t old_fs;
  198. old_fs = enable_sacf_uaccess();
  199. tmp1 = -256UL;
  200. asm volatile(
  201. " sacf 0\n"
  202. "0: mvcs 0(%0,%1),0(%2),%3\n"
  203. "7: jz 5f\n"
  204. "1: algr %0,%3\n"
  205. " la %1,256(%1)\n"
  206. " la %2,256(%2)\n"
  207. "2: mvcs 0(%0,%1),0(%2),%3\n"
  208. "8: jnz 1b\n"
  209. " j 5f\n"
  210. "3: la %4,255(%1)\n" /* %4 = ptr + 255 */
  211. " lghi %3,-4096\n"
  212. " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */
  213. " slgr %4,%1\n"
  214. " clgr %0,%4\n" /* copy crosses next page boundary? */
  215. " jnh 6f\n"
  216. "4: mvcs 0(%4,%1),0(%2),%3\n"
  217. "9: slgr %0,%4\n"
  218. " j 6f\n"
  219. "5: slgr %0,%0\n"
  220. "6: sacf 768\n"
  221. EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b)
  222. EX_TABLE(7b,3b) EX_TABLE(8b,3b) EX_TABLE(9b,6b)
  223. : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
  224. : : "cc", "memory");
  225. disable_sacf_uaccess(old_fs);
  226. return size;
  227. }
  228. unsigned long raw_copy_to_user(void __user *to, const void *from, unsigned long n)
  229. {
  230. if (copy_with_mvcos())
  231. return copy_to_user_mvcos(to, from, n);
  232. return copy_to_user_mvcs(to, from, n);
  233. }
  234. EXPORT_SYMBOL(raw_copy_to_user);
  235. static inline unsigned long copy_in_user_mvcos(void __user *to, const void __user *from,
  236. unsigned long size)
  237. {
  238. register unsigned long reg0 asm("0") = 0x010001UL;
  239. unsigned long tmp1, tmp2;
  240. tmp1 = -4096UL;
  241. /* FIXME: copy with reduced length. */
  242. asm volatile(
  243. "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
  244. " jz 2f\n"
  245. "1: algr %0,%3\n"
  246. " slgr %1,%3\n"
  247. " slgr %2,%3\n"
  248. " j 0b\n"
  249. "2:slgr %0,%0\n"
  250. "3: \n"
  251. EX_TABLE(0b,3b)
  252. : "+a" (size), "+a" (to), "+a" (from), "+a" (tmp1), "=a" (tmp2)
  253. : "d" (reg0) : "cc", "memory");
  254. return size;
  255. }
  256. static inline unsigned long copy_in_user_mvc(void __user *to, const void __user *from,
  257. unsigned long size)
  258. {
  259. mm_segment_t old_fs;
  260. unsigned long tmp1;
  261. old_fs = enable_sacf_uaccess();
  262. asm volatile(
  263. " sacf 256\n"
  264. " aghi %0,-1\n"
  265. " jo 5f\n"
  266. " bras %3,3f\n"
  267. "0: aghi %0,257\n"
  268. "1: mvc 0(1,%1),0(%2)\n"
  269. " la %1,1(%1)\n"
  270. " la %2,1(%2)\n"
  271. " aghi %0,-1\n"
  272. " jnz 1b\n"
  273. " j 5f\n"
  274. "2: mvc 0(256,%1),0(%2)\n"
  275. " la %1,256(%1)\n"
  276. " la %2,256(%2)\n"
  277. "3: aghi %0,-256\n"
  278. " jnm 2b\n"
  279. "4: ex %0,1b-0b(%3)\n"
  280. "5: slgr %0,%0\n"
  281. "6: sacf 768\n"
  282. EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
  283. : "+a" (size), "+a" (to), "+a" (from), "=a" (tmp1)
  284. : : "cc", "memory");
  285. disable_sacf_uaccess(old_fs);
  286. return size;
  287. }
  288. unsigned long raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
  289. {
  290. if (copy_with_mvcos())
  291. return copy_in_user_mvcos(to, from, n);
  292. return copy_in_user_mvc(to, from, n);
  293. }
  294. EXPORT_SYMBOL(raw_copy_in_user);
  295. static inline unsigned long clear_user_mvcos(void __user *to, unsigned long size)
  296. {
  297. register unsigned long reg0 asm("0") = 0x010000UL;
  298. unsigned long tmp1, tmp2;
  299. tmp1 = -4096UL;
  300. asm volatile(
  301. "0: .insn ss,0xc80000000000,0(%0,%1),0(%4),0\n"
  302. " jz 4f\n"
  303. "1: algr %0,%2\n"
  304. " slgr %1,%2\n"
  305. " j 0b\n"
  306. "2: la %3,4095(%1)\n"/* %4 = to + 4095 */
  307. " nr %3,%2\n" /* %4 = (to + 4095) & -4096 */
  308. " slgr %3,%1\n"
  309. " clgr %0,%3\n" /* copy crosses next page boundary? */
  310. " jnh 5f\n"
  311. "3: .insn ss,0xc80000000000,0(%3,%1),0(%4),0\n"
  312. " slgr %0,%3\n"
  313. " j 5f\n"
  314. "4: slgr %0,%0\n"
  315. "5:\n"
  316. EX_TABLE(0b,2b) EX_TABLE(3b,5b)
  317. : "+a" (size), "+a" (to), "+a" (tmp1), "=a" (tmp2)
  318. : "a" (empty_zero_page), "d" (reg0) : "cc", "memory");
  319. return size;
  320. }
  321. static inline unsigned long clear_user_xc(void __user *to, unsigned long size)
  322. {
  323. mm_segment_t old_fs;
  324. unsigned long tmp1, tmp2;
  325. old_fs = enable_sacf_uaccess();
  326. asm volatile(
  327. " sacf 256\n"
  328. " aghi %0,-1\n"
  329. " jo 5f\n"
  330. " bras %3,3f\n"
  331. " xc 0(1,%1),0(%1)\n"
  332. "0: aghi %0,257\n"
  333. " la %2,255(%1)\n" /* %2 = ptr + 255 */
  334. " srl %2,12\n"
  335. " sll %2,12\n" /* %2 = (ptr + 255) & -4096 */
  336. " slgr %2,%1\n"
  337. " clgr %0,%2\n" /* clear crosses next page boundary? */
  338. " jnh 5f\n"
  339. " aghi %2,-1\n"
  340. "1: ex %2,0(%3)\n"
  341. " aghi %2,1\n"
  342. " slgr %0,%2\n"
  343. " j 5f\n"
  344. "2: xc 0(256,%1),0(%1)\n"
  345. " la %1,256(%1)\n"
  346. "3: aghi %0,-256\n"
  347. " jnm 2b\n"
  348. "4: ex %0,0(%3)\n"
  349. "5: slgr %0,%0\n"
  350. "6: sacf 768\n"
  351. EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
  352. : "+a" (size), "+a" (to), "=a" (tmp1), "=a" (tmp2)
  353. : : "cc", "memory");
  354. disable_sacf_uaccess(old_fs);
  355. return size;
  356. }
  357. unsigned long __clear_user(void __user *to, unsigned long size)
  358. {
  359. if (copy_with_mvcos())
  360. return clear_user_mvcos(to, size);
  361. return clear_user_xc(to, size);
  362. }
  363. EXPORT_SYMBOL(__clear_user);
  364. static inline unsigned long strnlen_user_srst(const char __user *src,
  365. unsigned long size)
  366. {
  367. register unsigned long reg0 asm("0") = 0;
  368. unsigned long tmp1, tmp2;
  369. asm volatile(
  370. " la %2,0(%1)\n"
  371. " la %3,0(%0,%1)\n"
  372. " slgr %0,%0\n"
  373. " sacf 256\n"
  374. "0: srst %3,%2\n"
  375. " jo 0b\n"
  376. " la %0,1(%3)\n" /* strnlen_user results includes \0 */
  377. " slgr %0,%1\n"
  378. "1: sacf 768\n"
  379. EX_TABLE(0b,1b)
  380. : "+a" (size), "+a" (src), "=a" (tmp1), "=a" (tmp2)
  381. : "d" (reg0) : "cc", "memory");
  382. return size;
  383. }
  384. unsigned long __strnlen_user(const char __user *src, unsigned long size)
  385. {
  386. mm_segment_t old_fs;
  387. unsigned long len;
  388. if (unlikely(!size))
  389. return 0;
  390. old_fs = enable_sacf_uaccess();
  391. len = strnlen_user_srst(src, size);
  392. disable_sacf_uaccess(old_fs);
  393. return len;
  394. }
  395. EXPORT_SYMBOL(__strnlen_user);
  396. long __strncpy_from_user(char *dst, const char __user *src, long size)
  397. {
  398. size_t done, len, offset, len_str;
  399. if (unlikely(size <= 0))
  400. return 0;
  401. done = 0;
  402. do {
  403. offset = (size_t)src & (L1_CACHE_BYTES - 1);
  404. len = min(size - done, L1_CACHE_BYTES - offset);
  405. if (copy_from_user(dst, src, len))
  406. return -EFAULT;
  407. len_str = strnlen(dst, len);
  408. done += len_str;
  409. src += len_str;
  410. dst += len_str;
  411. } while ((len_str == len) && (done < size));
  412. return done;
  413. }
  414. EXPORT_SYMBOL(__strncpy_from_user);