diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-11-28 23:18:05 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-10 05:39:39 -0500 |
commit | c449c38b5df1fad556ea210deb6cff3b27323e49 (patch) | |
tree | 1469b4334e0f620586c875bd1e622b606b196d8d | |
parent | 6e7726e16fb5e8f1169dbfcb75e321ac871af827 (diff) |
[SPARC64]: Unaligned accesses to userspace are hard errors.
Userspace is forbidden from making unaligned loads and
stores. So if we get an unaligned trap due to a
{get,put}_user(), signal a fault and run the exception
handler.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | arch/sparc64/kernel/unaligned.c | 44 |
1 files changed, 31 insertions, 13 deletions
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index a9b765271b85..bc18d480dd1c 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c | |||
@@ -243,7 +243,7 @@ static inline int ok_for_kernel(unsigned int insn) | |||
243 | return !floating_point_load_or_store_p(insn); | 243 | return !floating_point_load_or_store_p(insn); |
244 | } | 244 | } |
245 | 245 | ||
246 | static void kernel_mna_trap_fault(void) | 246 | static void kernel_mna_trap_fault(int fixup_tstate_asi) |
247 | { | 247 | { |
248 | struct pt_regs *regs = current_thread_info()->kern_una_regs; | 248 | struct pt_regs *regs = current_thread_info()->kern_una_regs; |
249 | unsigned int insn = current_thread_info()->kern_una_insn; | 249 | unsigned int insn = current_thread_info()->kern_una_insn; |
@@ -274,18 +274,15 @@ static void kernel_mna_trap_fault(void) | |||
274 | regs->tpc = entry->fixup; | 274 | regs->tpc = entry->fixup; |
275 | regs->tnpc = regs->tpc + 4; | 275 | regs->tnpc = regs->tpc + 4; |
276 | 276 | ||
277 | regs->tstate &= ~TSTATE_ASI; | 277 | if (fixup_tstate_asi) { |
278 | regs->tstate |= (ASI_AIUS << 24UL); | 278 | regs->tstate &= ~TSTATE_ASI; |
279 | regs->tstate |= (ASI_AIUS << 24UL); | ||
280 | } | ||
279 | } | 281 | } |
280 | 282 | ||
281 | asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) | 283 | static void log_unaligned(struct pt_regs *regs) |
282 | { | 284 | { |
283 | static unsigned long count, last_time; | 285 | static unsigned long count, last_time; |
284 | enum direction dir = decode_direction(insn); | ||
285 | int size = decode_access_size(insn); | ||
286 | |||
287 | current_thread_info()->kern_una_regs = regs; | ||
288 | current_thread_info()->kern_una_insn = insn; | ||
289 | 286 | ||
290 | if (jiffies - last_time > 5 * HZ) | 287 | if (jiffies - last_time > 5 * HZ) |
291 | count = 0; | 288 | count = 0; |
@@ -295,6 +292,28 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) | |||
295 | printk("Kernel unaligned access at TPC[%lx] ", regs->tpc); | 292 | printk("Kernel unaligned access at TPC[%lx] ", regs->tpc); |
296 | print_symbol("%s\n", regs->tpc); | 293 | print_symbol("%s\n", regs->tpc); |
297 | } | 294 | } |
295 | } | ||
296 | |||
297 | asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) | ||
298 | { | ||
299 | enum direction dir = decode_direction(insn); | ||
300 | int size = decode_access_size(insn); | ||
301 | int orig_asi, asi; | ||
302 | |||
303 | current_thread_info()->kern_una_regs = regs; | ||
304 | current_thread_info()->kern_una_insn = insn; | ||
305 | |||
306 | orig_asi = asi = decode_asi(insn, regs); | ||
307 | |||
308 | /* If this is a {get,put}_user() on an unaligned userspace pointer, | ||
309 | * just signal a fault and do not log the event. | ||
310 | */ | ||
311 | if (asi == ASI_AIUS) { | ||
312 | kernel_mna_trap_fault(0); | ||
313 | return; | ||
314 | } | ||
315 | |||
316 | log_unaligned(regs); | ||
298 | 317 | ||
299 | if (!ok_for_kernel(insn) || dir == both) { | 318 | if (!ok_for_kernel(insn) || dir == both) { |
300 | printk("Unsupported unaligned load/store trap for kernel " | 319 | printk("Unsupported unaligned load/store trap for kernel " |
@@ -302,10 +321,10 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) | |||
302 | unaligned_panic("Kernel does fpu/atomic " | 321 | unaligned_panic("Kernel does fpu/atomic " |
303 | "unaligned load/store.", regs); | 322 | "unaligned load/store.", regs); |
304 | 323 | ||
305 | kernel_mna_trap_fault(); | 324 | kernel_mna_trap_fault(0); |
306 | } else { | 325 | } else { |
307 | unsigned long addr, *reg_addr; | 326 | unsigned long addr, *reg_addr; |
308 | int orig_asi, asi, err; | 327 | int err; |
309 | 328 | ||
310 | addr = compute_effective_address(regs, insn, | 329 | addr = compute_effective_address(regs, insn, |
311 | ((insn >> 25) & 0x1f)); | 330 | ((insn >> 25) & 0x1f)); |
@@ -315,7 +334,6 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) | |||
315 | regs->tpc, dirstrings[dir], addr, size, | 334 | regs->tpc, dirstrings[dir], addr, size, |
316 | regs->u_regs[UREG_RETPC]); | 335 | regs->u_regs[UREG_RETPC]); |
317 | #endif | 336 | #endif |
318 | orig_asi = asi = decode_asi(insn, regs); | ||
319 | switch (asi) { | 337 | switch (asi) { |
320 | case ASI_NL: | 338 | case ASI_NL: |
321 | case ASI_AIUPL: | 339 | case ASI_AIUPL: |
@@ -365,7 +383,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) | |||
365 | /* Not reached... */ | 383 | /* Not reached... */ |
366 | } | 384 | } |
367 | if (unlikely(err)) | 385 | if (unlikely(err)) |
368 | kernel_mna_trap_fault(); | 386 | kernel_mna_trap_fault(1); |
369 | else | 387 | else |
370 | advance(regs); | 388 | advance(regs); |
371 | } | 389 | } |