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 <asm/alignment.h> 17 #include <asm/processor.h> 18 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 31 core_param(alignment, se_usermode, int, 0600); 32 33 void inc_unaligned_byte_access(void) 34 { 35 se_half++; 36 } 37 38 void inc_unaligned_word_access(void) 39 { 40 se_word++; 41 } 42 43 void inc_unaligned_dword_access(void) 44 { 45 se_dword++; 46 } 47 48 void inc_unaligned_multi_access(void) 49 { 50 se_multi++; 51 } 52 53 void inc_unaligned_user_access(void) 54 { 55 se_user++; 56 } 57 58 void inc_unaligned_kernel_access(void) 59 { 60 se_sys++; 61 } 62 63 /* 64 * This defaults to the global policy which can be set from the command 65 * line, while processes can overload their preferences via prctl(). 66 */ 67 unsigned int unaligned_user_action(void) 68 { 69 unsigned int action = se_usermode; 70 71 if (current->thread.flags & SH_THREAD_UAC_SIGBUS) { 72 action &= ~UM_FIXUP; 73 action |= UM_SIGNAL; 74 } 75 76 if (current->thread.flags & SH_THREAD_UAC_NOPRINT) 77 action &= ~UM_WARN; 78 79 return action; 80 } 81 82 int get_unalign_ctl(struct task_struct *tsk, unsigned long addr) 83 { 84 return put_user(tsk->thread.flags & SH_THREAD_UAC_MASK, 85 (unsigned int __user *)addr); 86 } 87 88 int set_unalign_ctl(struct task_struct *tsk, unsigned int val) 89 { 90 tsk->thread.flags = (tsk->thread.flags & ~SH_THREAD_UAC_MASK) | 91 (val & SH_THREAD_UAC_MASK); 92 return 0; 93 } 94 95 void unaligned_fixups_notify(struct task_struct *tsk, insn_size_t insn, 96 struct pt_regs *regs) 97 { 98 if (user_mode(regs) && (se_usermode & UM_WARN) && printk_ratelimit()) 99 pr_notice("Fixing up unaligned userspace access " 100 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", 101 tsk->comm, task_pid_nr(tsk), 102 (void *)instruction_pointer(regs), insn); 103 else if (se_kernmode_warn && printk_ratelimit()) 104 pr_notice("Fixing up unaligned kernel access " 105 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", 106 tsk->comm, task_pid_nr(tsk), 107 (void *)instruction_pointer(regs), insn); 108 } 109 110 static const char *se_usermode_action[] = { 111 "ignored", 112 "warn", 113 "fixup", 114 "fixup+warn", 115 "signal", 116 "signal+warn" 117 }; 118 119 static int alignment_proc_show(struct seq_file *m, void *v) 120 { 121 seq_printf(m, "User:\t\t%lu\n", se_user); 122 seq_printf(m, "System:\t\t%lu\n", se_sys); 123 seq_printf(m, "Half:\t\t%lu\n", se_half); 124 seq_printf(m, "Word:\t\t%lu\n", se_word); 125 seq_printf(m, "DWord:\t\t%lu\n", se_dword); 126 seq_printf(m, "Multi:\t\t%lu\n", se_multi); 127 seq_printf(m, "User faults:\t%i (%s)\n", se_usermode, 128 se_usermode_action[se_usermode]); 129 seq_printf(m, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn, 130 se_kernmode_warn ? "+warn" : ""); 131 return 0; 132 } 133 134 static int alignment_proc_open(struct inode *inode, struct file *file) 135 { 136 return single_open(file, alignment_proc_show, NULL); 137 } 138 139 static ssize_t alignment_proc_write(struct file *file, 140 const char __user *buffer, size_t count, loff_t *pos) 141 { 142 int *data = PDE(file->f_path.dentry->d_inode)->data; 143 char mode; 144 145 if (count > 0) { 146 if (get_user(mode, buffer)) 147 return -EFAULT; 148 if (mode >= '0' && mode <= '5') 149 *data = mode - '0'; 150 } 151 return count; 152 } 153 154 static const struct file_operations alignment_proc_fops = { 155 .owner = THIS_MODULE, 156 .open = alignment_proc_open, 157 .read = seq_read, 158 .llseek = seq_lseek, 159 .release = single_release, 160 .write = alignment_proc_write, 161 }; 162 163 /* 164 * This needs to be done after sysctl_init, otherwise sys/ will be 165 * overwritten. Actually, this shouldn't be in sys/ at all since 166 * it isn't a sysctl, and it doesn't contain sysctl information. 167 * We now locate it in /proc/cpu/alignment instead. 168 */ 169 static int __init alignment_init(void) 170 { 171 struct proc_dir_entry *dir, *res; 172 173 dir = proc_mkdir("cpu", NULL); 174 if (!dir) 175 return -ENOMEM; 176 177 res = proc_create_data("alignment", S_IWUSR | S_IRUGO, dir, 178 &alignment_proc_fops, &se_usermode); 179 if (!res) 180 return -ENOMEM; 181 182 res = proc_create_data("kernel_alignment", S_IWUSR | S_IRUGO, dir, 183 &alignment_proc_fops, &se_kernmode_warn); 184 if (!res) 185 return -ENOMEM; 186 187 return 0; 188 } 189 fs_initcall(alignment_init); 190