Commit e17587b5 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6:
  [AVR32] Fix wrong pt_regs in critical exception handler
  [AVR32] Fix copy_to_user_page() breakage
  [AVR32] Follow the rules when dealing with the OCD system
  [AVR32] Clean up OCD register usage
  [AVR32] Implement irqflags trace and lockdep support
  [AVR32] Implement stacktrace support
  [AVR32] Kconfig: Use def_bool instead of bool + default
  [AVR32] Fix invalid status register bit definitions in asm/ptrace.h
  [AVR32] Add TIF_RESTORE_SIGMASK to the work masks
parents 29ac0052 5998a3cf
......@@ -6,8 +6,7 @@
mainmenu "Linux Kernel Configuration"
config AVR32
bool
default y
def_bool y
# With EMBEDDED=n, we get lots of stuff automatically selected
# that we usually don't need on AVR32.
select EMBEDDED
......@@ -20,51 +19,49 @@ config AVR32
http://avr32linux.org/.
config GENERIC_GPIO
bool
default y
def_bool y
config GENERIC_HARDIRQS
bool
default y
def_bool y
config STACKTRACE_SUPPORT
def_bool y
config LOCKDEP_SUPPORT
def_bool y
config TRACE_IRQFLAGS_SUPPORT
def_bool y
config HARDIRQS_SW_RESEND
bool
default y
def_bool y
config GENERIC_IRQ_PROBE
bool
default y
def_bool y
config RWSEM_GENERIC_SPINLOCK
bool
default y
def_bool y
config GENERIC_TIME
bool
default y
def_bool y
config RWSEM_XCHGADD_ALGORITHM
bool
def_bool n
config ARCH_HAS_ILOG2_U32
bool
default n
def_bool n
config ARCH_HAS_ILOG2_U64
bool
default n
def_bool n
config GENERIC_HWEIGHT
bool
default y
def_bool y
config GENERIC_CALIBRATE_DELAY
bool
default y
def_bool y
config GENERIC_BUG
bool
default y
def_bool y
depends on BUG
source "init/Kconfig"
......@@ -139,28 +136,22 @@ config PHYS_OFFSET
source "kernel/Kconfig.preempt"
config HAVE_ARCH_BOOTMEM_NODE
bool
default n
def_bool n
config ARCH_HAVE_MEMORY_PRESENT
bool
default n
def_bool n
config NEED_NODE_MEMMAP_SIZE
bool
default n
def_bool n
config ARCH_FLATMEM_ENABLE
bool
default y
def_bool y
config ARCH_DISCONTIGMEM_ENABLE
bool
default n
def_bool n
config ARCH_SPARSEMEM_ENABLE
bool
default n
def_bool n
source "mm/Kconfig"
......
......@@ -11,3 +11,4 @@ obj-y += signal.o sys_avr32.o process.o time.o
obj-y += init_task.o switch_to.o cpu.o
obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
......@@ -21,5 +21,7 @@ void foo(void)
OFFSET(TI_flags, thread_info, flags);
OFFSET(TI_cpu, thread_info, cpu);
OFFSET(TI_preempt_count, thread_info, preempt_count);
OFFSET(TI_rar_saved, thread_info, rar_saved);
OFFSET(TI_rsr_saved, thread_info, rsr_saved);
OFFSET(TI_restart_block, thread_info, restart_block);
}
......@@ -264,16 +264,7 @@ syscall_exit_work:
3: bld r1, TIF_BREAKPOINT
brcc syscall_exit_cont
mfsr r3, SYSREG_TLBEHI
lddsp r2, sp[REG_PC]
andl r3, 0xff, COH
lsl r3, 1
sbr r3, 30
sbr r3, 0
mtdr DBGREG_BWA2A, r2
mtdr DBGREG_BWC2A, r3
rjmp syscall_exit_cont
rjmp enter_monitor_mode
/* The slow path of the TLB miss handler */
page_table_not_present:
......@@ -288,11 +279,16 @@ page_not_present:
rjmp ret_from_exception
/* This function expects to find offending PC in SYSREG_RAR_EX */
.type save_full_context_ex, @function
.align 2
save_full_context_ex:
mfsr r11, SYSREG_RAR_EX
sub r9, pc, . - debug_trampoline
mfsr r8, SYSREG_RSR_EX
cp.w r9, r11
breq 3f
mov r12, r8
andh r8, (MODE_MASK >> 16), COH
mfsr r11, SYSREG_RAR_EX
brne 2f
1: pushm r11, r12 /* PC and SR */
......@@ -303,10 +299,25 @@ save_full_context_ex:
stdsp sp[4], r10 /* replace saved SP */
rjmp 1b
/*
* The debug handler set up a trampoline to make us
* automatically enter monitor mode upon return, but since
* we're saving the full context, we must assume that the
* exception handler might want to alter the return address
* and/or status register. So we need to restore the original
* context and enter monitor mode manually after the exception
* has been handled.
*/
3: get_thread_info r8
ld.w r11, r8[TI_rar_saved]
ld.w r12, r8[TI_rsr_saved]
rjmp 1b
.size save_full_context_ex, . - save_full_context_ex
/* Low-level exception handlers */
handle_critical:
pushm r12
pushm r0-r12
sub sp, 4
stmts --sp, r0-lr
rcall save_full_context_ex
mfsr r12, SYSREG_ECR
mov r11, sp
......@@ -439,6 +450,7 @@ do_fpe_ll:
ret_from_exception:
mask_interrupts
lddsp r4, sp[REG_SR]
andh r4, (MODE_MASK >> 16), COH
brne fault_resume_kernel
......@@ -515,119 +527,124 @@ fault_exit_work:
2: bld r1, TIF_BREAKPOINT
brcc fault_resume_user
mfsr r3, SYSREG_TLBEHI
lddsp r2, sp[REG_PC]
andl r3, 0xff, COH
lsl r3, 1
sbr r3, 30
sbr r3, 0
mtdr DBGREG_BWA2A, r2
mtdr DBGREG_BWC2A, r3
rjmp fault_resume_user
/* If we get a debug trap from privileged context we end up here */
handle_debug_priv:
/* Fix up LR and SP in regs. r11 contains the mode we came from */
rjmp enter_monitor_mode
.section .kprobes.text, "ax", @progbits
.type handle_debug, @function
handle_debug:
sub sp, 4 /* r12_orig */
stmts --sp, r0-lr
mfsr r8, SYSREG_RAR_DBG
mfsr r9, SYSREG_RSR_DBG
unmask_exceptions
pushm r8-r9
bfextu r9, r9, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE
brne debug_fixup_regs
.Ldebug_fixup_cont:
#ifdef CONFIG_TRACE_IRQFLAGS
rcall trace_hardirqs_off
#endif
mov r12, sp
rcall do_debug
mov sp, r12
lddsp r2, sp[REG_SR]
bfextu r3, r2, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE
brne debug_resume_kernel
get_thread_info r0
ld.w r1, r0[TI_flags]
mov r2, _TIF_DBGWORK_MASK
tst r1, r2
brne debug_exit_work
bld r1, TIF_SINGLE_STEP
brcc 1f
mfdr r4, OCD_DC
sbr r4, OCD_DC_SS_BIT
mtdr OCD_DC, r4
1: popm r10,r11
mask_exceptions
mtsr SYSREG_RSR_DBG, r11
mtsr SYSREG_RAR_DBG, r10
#ifdef CONFIG_TRACE_IRQFLAGS
rcall trace_hardirqs_on
1:
#endif
ldmts sp++, r0-lr
sub sp, -4
retd
.size handle_debug, . - handle_debug
/* Mode of the trapped context is in r9 */
.type debug_fixup_regs, @function
debug_fixup_regs:
mfsr r8, SYSREG_SR
mov r9, r8
andh r8, hi(~MODE_MASK)
or r8, r11
mov r10, r8
bfins r8, r9, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE
mtsr SYSREG_SR, r8
sub pc, -2
stdsp sp[REG_LR], lr
mtsr SYSREG_SR, r9
mtsr SYSREG_SR, r10
sub pc, -2
sub r10, sp, -FRAME_SIZE_FULL
stdsp sp[REG_SP], r10
mov r12, sp
rcall do_debug_priv
sub r8, sp, -FRAME_SIZE_FULL
stdsp sp[REG_SP], r8
rjmp .Ldebug_fixup_cont
.size debug_fixup_regs, . - debug_fixup_regs
/* Now, put everything back */
ssrf SR_EM_BIT
.type debug_resume_kernel, @function
debug_resume_kernel:
mask_exceptions
popm r10, r11
mtsr SYSREG_RAR_DBG, r10
mtsr SYSREG_RSR_DBG, r11
mfsr r8, SYSREG_SR
mov r9, r8
andh r8, hi(~MODE_MASK)
andh r11, hi(MODE_MASK)
or r8, r11
mtsr SYSREG_SR, r8
#ifdef CONFIG_TRACE_IRQFLAGS
bld r11, SYSREG_GM_OFFSET
brcc 1f
rcall trace_hardirqs_on
1:
#endif
mfsr r2, SYSREG_SR
mov r1, r2
bfins r2, r3, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE
mtsr SYSREG_SR, r2
sub pc, -2
popm lr
mtsr SYSREG_SR, r9
mtsr SYSREG_SR, r1
sub pc, -2
sub sp, -4 /* skip SP */
popm r0-r12
sub sp, -4
retd
.size debug_resume_kernel, . - debug_resume_kernel
.type debug_exit_work, @function
debug_exit_work:
/*
* At this point, everything is masked, that is, interrupts,
* exceptions and debugging traps. We might get called from
* interrupt or exception context in some rare cases, but this
* will be taken care of by do_debug(), so we're not going to
* do a 100% correct context save here.
* We must return from Monitor Mode using a retd, and we must
* not schedule since that involves the D bit in SR getting
* cleared by something other than the debug hardware. This
* may cause undefined behaviour according to the Architecture
* manual.
*
* So we fix up the return address and status and return to a
* stub below in Exception mode. From there, we can follow the
* normal exception return path.
*
* The real return address and status registers are stored on
* the stack in the way the exception return path understands,
* so no need to fix anything up there.
*/
handle_debug:
sub sp, 4 /* r12_orig */
stmts --sp, r0-lr
mfsr r10, SYSREG_RAR_DBG
mfsr r11, SYSREG_RSR_DBG
unmask_exceptions
pushm r10,r11
andh r11, (MODE_MASK >> 16), COH
brne handle_debug_priv
mov r12, sp
rcall do_debug
lddsp r10, sp[REG_SR]
andh r10, (MODE_MASK >> 16), COH
breq debug_resume_user
debug_restore_all:
popm r10,r11
mask_exceptions
mtsr SYSREG_RSR_DBG, r11
mtsr SYSREG_RAR_DBG, r10
ldmts sp++, r0-lr
sub sp, -4
sub r8, pc, . - fault_exit_work
mtsr SYSREG_RAR_DBG, r8
mov r9, 0
orh r9, hi(SR_EM | SR_GM | MODE_EXCEPTION)
mtsr SYSREG_RSR_DBG, r9
sub pc, -2
retd
debug_resume_user:
get_thread_info r0
mask_interrupts
ld.w r1, r0[TI_flags]
andl r1, _TIF_DBGWORK_MASK, COH
breq debug_restore_all
1: bld r1, TIF_NEED_RESCHED
brcc 2f
unmask_interrupts
rcall schedule
mask_interrupts
ld.w r1, r0[TI_flags]
rjmp 1b
2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
tst r1, r2
breq 3f
unmask_interrupts
mov r12, sp
mov r11, r0
rcall do_notify_resume
mask_interrupts
ld.w r1, r0[TI_flags]
rjmp 1b
3: bld r1, TIF_SINGLE_STEP
brcc debug_restore_all
mfdr r2, DBGREG_DC
sbr r2, DC_SS_BIT
mtdr DBGREG_DC, r2
rjmp debug_restore_all
.size debug_exit_work, . - debug_exit_work
.set rsr_int0, SYSREG_RSR_INT0
.set rsr_int1, SYSREG_RSR_INT1
......@@ -675,7 +692,11 @@ irq_level\level:
andl r1, _TIF_WORK_MASK, COH
brne irq_exit_work
1: popm r8-r9
1:
#ifdef CONFIG_TRACE_IRQFLAGS
rcall trace_hardirqs_on
#endif
popm r8-r9
mtsr rar_int\level, r8
mtsr rsr_int\level, r9
ldmts sp++,r0-lr
......@@ -748,3 +769,53 @@ cpu_idle_enable_int_and_exit:
IRQ_LEVEL 1
IRQ_LEVEL 2
IRQ_LEVEL 3
.section .kprobes.text, "ax", @progbits
.type enter_monitor_mode, @function
enter_monitor_mode:
/*
* We need to enter monitor mode to do a single step. The
* monitor code will alter the return address so that we
* return directly to the user instead of returning here.
*/
breakpoint
rjmp breakpoint_failed
.size enter_monitor_mode, . - enter_monitor_mode
.type debug_trampoline, @function
.global debug_trampoline
debug_trampoline:
/*
* Save the registers on the stack so that the monitor code
* can find them easily.
*/
sub sp, 4 /* r12_orig */
stmts --sp, r0-lr
get_thread_info r0
ld.w r8, r0[TI_rar_saved]
ld.w r9, r0[TI_rsr_saved]
pushm r8-r9
/*
* The monitor code will alter the return address so we don't
* return here.
*/
breakpoint
rjmp breakpoint_failed
.size debug_trampoline, . - debug_trampoline
.type breakpoint_failed, @function
breakpoint_failed:
/*
* Something went wrong. Perhaps the debug hardware isn't
* enabled?
*/
lda.w r12, msg_breakpoint_failed
mov r11, sp
mov r10, 9 /* SIGKILL */
call die
1: rjmp 1b
msg_breakpoint_failed:
.asciz "Failed to enter Debug Mode"
......@@ -70,9 +70,9 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
BUG_ON(!(sysreg_read(SR) & SYSREG_BIT(SR_D)));
dc = __mfdr(DBGREG_DC);
dc |= DC_SS;
__mtdr(DBGREG_DC, dc);
dc = ocd_read(DC);
dc |= 1 << OCD_DC_SS_BIT;
ocd_write(DC, dc);
/*
* We must run the instruction from its original location
......@@ -91,9 +91,9 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
pr_debug("resuming execution at PC=%08lx\n", regs->pc);
dc = __mfdr(DBGREG_DC);
dc &= ~DC_SS;
__mtdr(DBGREG_DC, dc);
dc = ocd_read(DC);
dc &= ~(1 << OCD_DC_SS_BIT);
ocd_write(DC, dc);
*p->addr = BREAKPOINT_INSTRUCTION;
flush_icache_range((unsigned long)p->addr,
......@@ -261,7 +261,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
int __init arch_init_kprobes(void)
{
printk("KPROBES: Enabling monitor mode (MM|DBE)...\n");
__mtdr(DBGREG_DC, DC_MM | DC_DBE);
ocd_write(DC, (1 << OCD_DC_MM_BIT) | (1 << OCD_DC_DBE_BIT));
/* TODO: Register kretprobe trampoline */
return 0;
......
......@@ -55,8 +55,8 @@ void machine_power_off(void)
void machine_restart(char *cmd)
{
__mtdr(DBGREG_DC, DC_DBE);
__mtdr(DBGREG_DC, DC_RES);
ocd_write(DC, (1 << OCD_DC_DBE_BIT));
ocd_write(DC, (1 << OCD_DC_RES_BIT));
while (1) ;
}
......@@ -287,10 +287,11 @@ void show_regs_log_lvl(struct pt_regs *regs, const char *log_lvl)
regs->sr & SR_N ? 'N' : 'n',
regs->sr & SR_Z ? 'Z' : 'z',
regs->sr & SR_C ? 'C' : 'c');
printk("%sMode bits: %c%c%c%c%c%c%c%c%c\n", log_lvl,
printk("%sMode bits: %c%c%c%c%c%c%c%c%c%c\n", log_lvl,
regs->sr & SR_H ? 'H' : 'h',
regs->sr & SR_R ? 'R' : 'r',
regs->sr & SR_J ? 'J' : 'j',
regs->sr & SR_DM ? 'M' : 'm',
regs->sr & SR_D ? 'D' : 'd',
regs->sr & SR_EM ? 'E' : 'e',
regs->sr & SR_I3M ? '3' : '.',
regs->sr & SR_I2M ? '2' : '.',
......
This diff is collapsed.
/*
* Stack trace management functions
*
* Copyright (C) 2007 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/sched.h>
#include <linux/stacktrace.h>
#include <linux/thread_info.h>
register unsigned long current_frame_pointer asm("r7");
struct stackframe {
unsigned long lr;
unsigned long fp;
};
/*
* Save stack-backtrace addresses into a stack_trace buffer.
*/
void save_stack_trace(struct stack_trace *trace)
{
unsigned long low, high;
unsigned long fp;
struct stackframe *frame;
int skip = trace->skip;
low = (unsigned long)task_stack_page(current);
high = low + THREAD_SIZE;
fp = current_frame_pointer;
while (fp >= low && fp <= (high - 8)) {
frame = (struct stackframe *)fp;
if (skip) {
skip--;
} else {
trace->entries[trace->nr_entries++] = frame->lr;
if (trace->nr_entries >= trace->max_entries)
break;
}
/*
* The next frame must be at a higher address than the
* current frame.
*/
low = fp + 8;
fp = frame->fp;
}
}
......@@ -39,7 +39,7 @@ void NORET_TYPE die(const char *str, struct pt_regs *regs, long err)
printk("FRAME_POINTER ");
#endif
if (current_cpu_data.features & AVR32_FEATURE_OCD) {
unsigned long did = __mfdr(DBGREG_DID);
unsigned long did = ocd_read(DID);
printk("chip: 0x%03lx:0x%04lx rev %lu\n",
(did >> 1) & 0x7ff,
(did >> 12) & 0x7fff,
......
......@@ -77,10 +77,10 @@ SECTIONS
. = 0x100;
*(.scall.text)
*(.irq.text)
KPROBES_TEXT
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
KPROBES_TEXT
*(.fixup)
*(.gnu.warning)
_etext = .;
......
......@@ -122,16 +122,6 @@ void flush_icache_page(struct vm_area_struct *vma, struct page *page)
}
}
/*
* This one is used by copy_to_user_page()
*/
void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
unsigned long addr, int len)
{
if (vma->vm_flags & VM_EXEC)
flush_icache_range(addr, addr + len);
}
asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len)
{
int ret;
......@@ -159,3 +149,13 @@ asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len)
out:
return ret;
}
void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
unsigned long vaddr, void *dst, const void *src,
unsigned long len)
{
memcpy(dst, src, len);
if (vma->vm_flags & VM_EXEC)
flush_icache_range((unsigned long)dst,
(unsigned long)dst + len);
}
......@@ -116,15 +116,16 @@ extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
* flush with all configurations.
*/
extern void flush_icache_range(unsigned long start, unsigned long end);
extern void flush_icache_user_range(struct vm_area_struct *vma,
struct page *page,
unsigned long addr, int len);
#define copy_to_user_page(vma, page, vaddr, dst, src, len) do { \
memcpy(dst, src, len); \
flush_icache_user_range(vma, page, vaddr, len); \
} while(0)
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
memcpy(dst, src, len)
extern void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
unsigned long vaddr, void *dst, const void *src,
unsigned long len);
static inline void copy_from_user_page(struct vm_area_struct *vma,
struct page *page, unsigned long vaddr, void *dst,
const void *src, unsigned long len)
{
memcpy(dst, src, len);
}
#endif /* __ASM_AVR32_CACHEFLUSH_H */
This diff is collapsed.
......@@ -139,6 +139,9 @@ extern void show_regs_log_lvl(struct pt_regs *regs, const char *log_lvl);
extern void show_stack_log_lvl(struct task_struct *tsk, unsigned long sp,