alignment.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * Alignment access counters and corresponding user-space interfaces.
  3. *
  4. * Copyright (C) 2009 ST Microelectronics
  5. * Copyright (C) 2009 - 2010 Paul Mundt
  6. *
  7. * This file is subject to the terms and conditions of the GNU General Public
  8. * License. See the file "COPYING" in the main directory of this archive
  9. * for more details.
  10. */
  11. #include <linux/module.h>
  12. #include <linux/kernel.h>
  13. #include <linux/seq_file.h>
  14. #include <linux/proc_fs.h>
  15. #include <linux/uaccess.h>
  16. #include <linux/ratelimit.h>
  17. #include <asm/alignment.h>
  18. #include <asm/processor.h>
  19. static unsigned long se_user;
  20. static unsigned long se_sys;
  21. static unsigned long se_half;
  22. static unsigned long se_word;
  23. static unsigned long se_dword;
  24. static unsigned long se_multi;
  25. /* bitfield: 1: warn 2: fixup 4: signal -> combinations 2|4 && 1|2|4 are not
  26. valid! */
  27. static int se_usermode = UM_WARN | UM_FIXUP;
  28. /* 0: no warning 1: print a warning message, disabled by default */
  29. static int se_kernmode_warn;
  30. core_param(alignment, se_usermode, int, 0600);
  31. void inc_unaligned_byte_access(void)
  32. {
  33. se_half++;
  34. }
  35. void inc_unaligned_word_access(void)
  36. {
  37. se_word++;
  38. }
  39. void inc_unaligned_dword_access(void)
  40. {
  41. se_dword++;
  42. }
  43. void inc_unaligned_multi_access(void)
  44. {
  45. se_multi++;
  46. }
  47. void inc_unaligned_user_access(void)
  48. {
  49. se_user++;
  50. }
  51. void inc_unaligned_kernel_access(void)
  52. {
  53. se_sys++;
  54. }
  55. /*
  56. * This defaults to the global policy which can be set from the command
  57. * line, while processes can overload their preferences via prctl().
  58. */
  59. unsigned int unaligned_user_action(void)
  60. {
  61. unsigned int action = se_usermode;
  62. if (current->thread.flags & SH_THREAD_UAC_SIGBUS) {
  63. action &= ~UM_FIXUP;
  64. action |= UM_SIGNAL;
  65. }
  66. if (current->thread.flags & SH_THREAD_UAC_NOPRINT)
  67. action &= ~UM_WARN;
  68. return action;
  69. }
  70. int get_unalign_ctl(struct task_struct *tsk, unsigned long addr)
  71. {
  72. return put_user(tsk->thread.flags & SH_THREAD_UAC_MASK,
  73. (unsigned int __user *)addr);
  74. }
  75. int set_unalign_ctl(struct task_struct *tsk, unsigned int val)
  76. {
  77. tsk->thread.flags = (tsk->thread.flags & ~SH_THREAD_UAC_MASK) |
  78. (val & SH_THREAD_UAC_MASK);
  79. return 0;
  80. }
  81. void unaligned_fixups_notify(struct task_struct *tsk, insn_size_t insn,
  82. struct pt_regs *regs)
  83. {
  84. if (user_mode(regs) && (se_usermode & UM_WARN))
  85. pr_notice_ratelimited("Fixing up unaligned userspace access "
  86. "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
  87. tsk->comm, task_pid_nr(tsk),
  88. (void *)instruction_pointer(regs), insn);
  89. else if (se_kernmode_warn)
  90. pr_notice_ratelimited("Fixing up unaligned kernel access "
  91. "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
  92. tsk->comm, task_pid_nr(tsk),
  93. (void *)instruction_pointer(regs), insn);
  94. }
  95. static const char *se_usermode_action[] = {
  96. "ignored",
  97. "warn",
  98. "fixup",
  99. "fixup+warn",
  100. "signal",
  101. "signal+warn"
  102. };
  103. static int alignment_proc_show(struct seq_file *m, void *v)
  104. {
  105. seq_printf(m, "User:\t\t%lu\n", se_user);
  106. seq_printf(m, "System:\t\t%lu\n", se_sys);
  107. seq_printf(m, "Half:\t\t%lu\n", se_half);
  108. seq_printf(m, "Word:\t\t%lu\n", se_word);
  109. seq_printf(m, "DWord:\t\t%lu\n", se_dword);
  110. seq_printf(m, "Multi:\t\t%lu\n", se_multi);
  111. seq_printf(m, "User faults:\t%i (%s)\n", se_usermode,
  112. se_usermode_action[se_usermode]);
  113. seq_printf(m, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn,
  114. se_kernmode_warn ? "+warn" : "");
  115. return 0;
  116. }
  117. static int alignment_proc_open(struct inode *inode, struct file *file)
  118. {
  119. return single_open(file, alignment_proc_show, NULL);
  120. }
  121. static ssize_t alignment_proc_write(struct file *file,
  122. const char __user *buffer, size_t count, loff_t *pos)
  123. {
  124. int *data = PDE_DATA(file_inode(file));
  125. char mode;
  126. if (count > 0) {
  127. if (get_user(mode, buffer))
  128. return -EFAULT;
  129. if (mode >= '0' && mode <= '5')
  130. *data = mode - '0';
  131. }
  132. return count;
  133. }
  134. static const struct file_operations alignment_proc_fops = {
  135. .owner = THIS_MODULE,
  136. .open = alignment_proc_open,
  137. .read = seq_read,
  138. .llseek = seq_lseek,
  139. .release = single_release,
  140. .write = alignment_proc_write,
  141. };
  142. /*
  143. * This needs to be done after sysctl_init, otherwise sys/ will be
  144. * overwritten. Actually, this shouldn't be in sys/ at all since
  145. * it isn't a sysctl, and it doesn't contain sysctl information.
  146. * We now locate it in /proc/cpu/alignment instead.
  147. */
  148. static int __init alignment_init(void)
  149. {
  150. struct proc_dir_entry *dir, *res;
  151. dir = proc_mkdir("cpu", NULL);
  152. if (!dir)
  153. return -ENOMEM;
  154. res = proc_create_data("alignment", S_IWUSR | S_IRUGO, dir,
  155. &alignment_proc_fops, &se_usermode);
  156. if (!res)
  157. return -ENOMEM;
  158. res = proc_create_data("kernel_alignment", S_IWUSR | S_IRUGO, dir,
  159. &alignment_proc_fops, &se_kernmode_warn);
  160. if (!res)
  161. return -ENOMEM;
  162. return 0;
  163. }
  164. fs_initcall(alignment_init);