maccess.c 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /*
  2. * Access kernel memory without faulting -- s390 specific implementation.
  3. *
  4. * Copyright IBM Corp. 2009
  5. *
  6. * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
  7. *
  8. */
  9. #include <linux/uaccess.h>
  10. #include <linux/kernel.h>
  11. #include <linux/types.h>
  12. #include <linux/errno.h>
  13. #include <asm/system.h>
  14. /*
  15. * This function writes to kernel memory bypassing DAT and possible
  16. * write protection. It copies one to four bytes from src to dst
  17. * using the stura instruction.
  18. * Returns the number of bytes copied or -EFAULT.
  19. */
  20. static long probe_kernel_write_odd(void *dst, const void *src, size_t size)
  21. {
  22. unsigned long count, aligned;
  23. int offset, mask;
  24. int rc = -EFAULT;
  25. aligned = (unsigned long) dst & ~3UL;
  26. offset = (unsigned long) dst & 3;
  27. count = min_t(unsigned long, 4 - offset, size);
  28. mask = (0xf << (4 - count)) & 0xf;
  29. mask >>= offset;
  30. asm volatile(
  31. " bras 1,0f\n"
  32. " icm 0,0,0(%3)\n"
  33. "0: l 0,0(%1)\n"
  34. " lra %1,0(%1)\n"
  35. "1: ex %2,0(1)\n"
  36. "2: stura 0,%1\n"
  37. " la %0,0\n"
  38. "3:\n"
  39. EX_TABLE(0b,3b) EX_TABLE(1b,3b) EX_TABLE(2b,3b)
  40. : "+d" (rc), "+a" (aligned)
  41. : "a" (mask), "a" (src) : "cc", "memory", "0", "1");
  42. return rc ? rc : count;
  43. }
  44. long probe_kernel_write(void *dst, const void *src, size_t size)
  45. {
  46. long copied = 0;
  47. while (size) {
  48. copied = probe_kernel_write_odd(dst, src, size);
  49. if (copied < 0)
  50. break;
  51. dst += copied;
  52. src += copied;
  53. size -= copied;
  54. }
  55. return copied < 0 ? -EFAULT : 0;
  56. }
  57. int memcpy_real(void *dest, void *src, size_t count)
  58. {
  59. register unsigned long _dest asm("2") = (unsigned long) dest;
  60. register unsigned long _len1 asm("3") = (unsigned long) count;
  61. register unsigned long _src asm("4") = (unsigned long) src;
  62. register unsigned long _len2 asm("5") = (unsigned long) count;
  63. unsigned long flags;
  64. int rc = -EFAULT;
  65. if (!count)
  66. return 0;
  67. flags = __arch_local_irq_stnsm(0xf8UL);
  68. asm volatile (
  69. "0: mvcle %1,%2,0x0\n"
  70. "1: jo 0b\n"
  71. " lhi %0,0x0\n"
  72. "2:\n"
  73. EX_TABLE(1b,2b)
  74. : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1),
  75. "+d" (_len2), "=m" (*((long *) dest))
  76. : "m" (*((long *) src))
  77. : "cc", "memory");
  78. arch_local_irq_restore(flags);
  79. return rc;
  80. }