| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2004-2006 Atmel Corporation | 
|  | 3 | * | 
|  | 4 | * This program is free software; you can redistribute it and/or modify | 
|  | 5 | * it under the terms of the GNU General Public License version 2 as | 
|  | 6 | * published by the Free Software Foundation. | 
|  | 7 | */ | 
|  | 8 |  | 
|  | 9 | /* | 
|  | 10 | * This file contains the low-level entry-points into the kernel, that is, | 
|  | 11 | * exception handlers, debug trap handlers, interrupt handlers and the | 
|  | 12 | * system call handler. | 
|  | 13 | */ | 
|  | 14 | #include <linux/errno.h> | 
|  | 15 |  | 
|  | 16 | #include <asm/asm.h> | 
|  | 17 | #include <asm/hardirq.h> | 
|  | 18 | #include <asm/irq.h> | 
|  | 19 | #include <asm/ocd.h> | 
|  | 20 | #include <asm/page.h> | 
|  | 21 | #include <asm/pgtable.h> | 
|  | 22 | #include <asm/ptrace.h> | 
|  | 23 | #include <asm/sysreg.h> | 
|  | 24 | #include <asm/thread_info.h> | 
|  | 25 | #include <asm/unistd.h> | 
|  | 26 |  | 
|  | 27 | #ifdef CONFIG_PREEMPT | 
|  | 28 | # define preempt_stop		mask_interrupts | 
|  | 29 | #else | 
|  | 30 | # define preempt_stop | 
|  | 31 | # define fault_resume_kernel	fault_restore_all | 
|  | 32 | #endif | 
|  | 33 |  | 
|  | 34 | #define __MASK(x)	((1 << (x)) - 1) | 
|  | 35 | #define IRQ_MASK	((__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) | \ | 
|  | 36 | (__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)) | 
|  | 37 |  | 
|  | 38 | .section .ex.text,"ax",@progbits | 
|  | 39 | .align	2 | 
|  | 40 | exception_vectors: | 
|  | 41 | bral	handle_critical | 
|  | 42 | .align	2 | 
|  | 43 | bral	handle_critical | 
|  | 44 | .align	2 | 
|  | 45 | bral	do_bus_error_write | 
|  | 46 | .align	2 | 
|  | 47 | bral	do_bus_error_read | 
|  | 48 | .align	2 | 
|  | 49 | bral	do_nmi_ll | 
|  | 50 | .align	2 | 
|  | 51 | bral	handle_address_fault | 
|  | 52 | .align	2 | 
|  | 53 | bral	handle_protection_fault | 
|  | 54 | .align	2 | 
|  | 55 | bral	handle_debug | 
|  | 56 | .align	2 | 
|  | 57 | bral	do_illegal_opcode_ll | 
|  | 58 | .align	2 | 
|  | 59 | bral	do_illegal_opcode_ll | 
|  | 60 | .align	2 | 
|  | 61 | bral	do_illegal_opcode_ll | 
|  | 62 | .align	2 | 
|  | 63 | bral	do_fpe_ll | 
|  | 64 | .align	2 | 
|  | 65 | bral	do_illegal_opcode_ll | 
|  | 66 | .align	2 | 
|  | 67 | bral	handle_address_fault | 
|  | 68 | .align	2 | 
|  | 69 | bral	handle_address_fault | 
|  | 70 | .align	2 | 
|  | 71 | bral	handle_protection_fault | 
|  | 72 | .align	2 | 
|  | 73 | bral	handle_protection_fault | 
|  | 74 | .align	2 | 
|  | 75 | bral	do_dtlb_modified | 
|  | 76 |  | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 77 | #define	tlbmiss_save	pushm	r0-r3 | 
|  | 78 | #define tlbmiss_restore	popm	r0-r3 | 
|  | 79 |  | 
| Haavard Skinnemoen | d704fb0 | 2008-01-14 21:42:56 +0100 | [diff] [blame] | 80 | .org	0x50 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 81 | .global	itlb_miss | 
|  | 82 | itlb_miss: | 
|  | 83 | tlbmiss_save | 
|  | 84 | rjmp	tlb_miss_common | 
|  | 85 |  | 
| Haavard Skinnemoen | d704fb0 | 2008-01-14 21:42:56 +0100 | [diff] [blame] | 86 | .org	0x60 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 87 | dtlb_miss_read: | 
|  | 88 | tlbmiss_save | 
|  | 89 | rjmp	tlb_miss_common | 
|  | 90 |  | 
| Haavard Skinnemoen | d704fb0 | 2008-01-14 21:42:56 +0100 | [diff] [blame] | 91 | .org	0x70 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 92 | dtlb_miss_write: | 
|  | 93 | tlbmiss_save | 
|  | 94 |  | 
|  | 95 | .global	tlb_miss_common | 
| Haavard Skinnemoen | d704fb0 | 2008-01-14 21:42:56 +0100 | [diff] [blame] | 96 | .align	2 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 97 | tlb_miss_common: | 
| Haavard Skinnemoen | c0c3e81 | 2007-03-14 13:59:13 +0100 | [diff] [blame] | 98 | mfsr	r0, SYSREG_TLBEAR | 
|  | 99 | mfsr	r1, SYSREG_PTBR | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 100 |  | 
| Haavard Skinnemoen | cfd23e9 | 2008-01-14 22:15:05 +0100 | [diff] [blame] | 101 | /* | 
|  | 102 | * First level lookup: The PGD contains virtual pointers to | 
|  | 103 | * the second-level page tables, but they may be NULL if not | 
|  | 104 | * present. | 
|  | 105 | */ | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 106 | pgtbl_lookup: | 
| Haavard Skinnemoen | c0c3e81 | 2007-03-14 13:59:13 +0100 | [diff] [blame] | 107 | lsr	r2, r0, PGDIR_SHIFT | 
|  | 108 | ld.w	r3, r1[r2 << 2] | 
|  | 109 | bfextu	r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT | 
| Haavard Skinnemoen | cfd23e9 | 2008-01-14 22:15:05 +0100 | [diff] [blame] | 110 | cp.w	r3, 0 | 
|  | 111 | breq	page_table_not_present | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 112 |  | 
|  | 113 | /* Second level lookup */ | 
| Haavard Skinnemoen | c0c3e81 | 2007-03-14 13:59:13 +0100 | [diff] [blame] | 114 | ld.w	r2, r3[r1 << 2] | 
|  | 115 | mfsr	r0, SYSREG_TLBARLO | 
|  | 116 | bld	r2, _PAGE_BIT_PRESENT | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 117 | brcc	page_not_present | 
|  | 118 |  | 
|  | 119 | /* Mark the page as accessed */ | 
| Haavard Skinnemoen | c0c3e81 | 2007-03-14 13:59:13 +0100 | [diff] [blame] | 120 | sbr	r2, _PAGE_BIT_ACCESSED | 
|  | 121 | st.w	r3[r1 << 2], r2 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 122 |  | 
|  | 123 | /* Drop software flags */ | 
| Haavard Skinnemoen | c0c3e81 | 2007-03-14 13:59:13 +0100 | [diff] [blame] | 124 | andl	r2, _PAGE_FLAGS_HARDWARE_MASK & 0xffff | 
|  | 125 | mtsr	SYSREG_TLBELO, r2 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 126 |  | 
|  | 127 | /* Figure out which entry we want to replace */ | 
| Haavard Skinnemoen | c0c3e81 | 2007-03-14 13:59:13 +0100 | [diff] [blame] | 128 | mfsr	r1, SYSREG_MMUCR | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 129 | clz	r2, r0 | 
|  | 130 | brcc	1f | 
| Haavard Skinnemoen | c0c3e81 | 2007-03-14 13:59:13 +0100 | [diff] [blame] | 131 | mov	r3, -1			/* All entries have been accessed, */ | 
|  | 132 | mov	r2, 0			/* so start at 0 */ | 
|  | 133 | mtsr	SYSREG_TLBARLO, r3	/* and reset TLBAR */ | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 134 |  | 
| Haavard Skinnemoen | c0c3e81 | 2007-03-14 13:59:13 +0100 | [diff] [blame] | 135 | 1:	bfins	r1, r2, SYSREG_DRP_OFFSET, SYSREG_DRP_SIZE | 
|  | 136 | mtsr	SYSREG_MMUCR, r1 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 137 | tlbw | 
|  | 138 |  | 
|  | 139 | tlbmiss_restore | 
|  | 140 | rete | 
|  | 141 |  | 
| Haavard Skinnemoen | cfd23e9 | 2008-01-14 22:15:05 +0100 | [diff] [blame] | 142 | /* The slow path of the TLB miss handler */ | 
|  | 143 | .align	2 | 
|  | 144 | page_table_not_present: | 
| Haavard Skinnemoen | a9a934f | 2008-01-14 23:11:26 +0100 | [diff] [blame] | 145 | /* Do we need to synchronize with swapper_pg_dir? */ | 
|  | 146 | bld	r0, 31 | 
|  | 147 | brcs	sync_with_swapper_pg_dir | 
|  | 148 |  | 
| Haavard Skinnemoen | cfd23e9 | 2008-01-14 22:15:05 +0100 | [diff] [blame] | 149 | page_not_present: | 
|  | 150 | tlbmiss_restore | 
|  | 151 | sub	sp, 4 | 
|  | 152 | stmts	--sp, r0-lr | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 153 | call	save_full_context_ex | 
| Haavard Skinnemoen | cfd23e9 | 2008-01-14 22:15:05 +0100 | [diff] [blame] | 154 | mfsr	r12, SYSREG_ECR | 
|  | 155 | mov	r11, sp | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 156 | call	do_page_fault | 
| Haavard Skinnemoen | cfd23e9 | 2008-01-14 22:15:05 +0100 | [diff] [blame] | 157 | rjmp	ret_from_exception | 
|  | 158 |  | 
| Haavard Skinnemoen | a9a934f | 2008-01-14 23:11:26 +0100 | [diff] [blame] | 159 | .align	2 | 
|  | 160 | sync_with_swapper_pg_dir: | 
|  | 161 | /* | 
|  | 162 | * If swapper_pg_dir contains a non-NULL second-level page | 
|  | 163 | * table pointer, copy it into the current PGD. If not, we | 
|  | 164 | * must handle it as a full-blown page fault. | 
|  | 165 | * | 
|  | 166 | * Jumping back to pgtbl_lookup causes an unnecessary lookup, | 
|  | 167 | * but it is guaranteed to be a cache hit, it won't happen | 
|  | 168 | * very often, and we absolutely do not want to sacrifice any | 
|  | 169 | * performance in the fast path in order to improve this. | 
|  | 170 | */ | 
|  | 171 | mov	r1, lo(swapper_pg_dir) | 
|  | 172 | orh	r1, hi(swapper_pg_dir) | 
|  | 173 | ld.w	r3, r1[r2 << 2] | 
|  | 174 | cp.w	r3, 0 | 
|  | 175 | breq	page_not_present | 
|  | 176 | mfsr	r1, SYSREG_PTBR | 
|  | 177 | st.w	r1[r2 << 2], r3 | 
|  | 178 | rjmp	pgtbl_lookup | 
|  | 179 |  | 
|  | 180 | /* | 
|  | 181 | * We currently have two bytes left at this point until we | 
|  | 182 | * crash into the system call handler... | 
|  | 183 | * | 
|  | 184 | * Don't worry, the assembler will let us know. | 
|  | 185 | */ | 
|  | 186 |  | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 187 |  | 
|  | 188 | /* ---                    System Call                    --- */ | 
|  | 189 |  | 
| Haavard Skinnemoen | d704fb0 | 2008-01-14 21:42:56 +0100 | [diff] [blame] | 190 | .org	0x100 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 191 | system_call: | 
| Philippe Rétornaz | a7e30b8 | 2007-10-10 18:52:24 -0400 | [diff] [blame] | 192 | #ifdef CONFIG_PREEMPT | 
|  | 193 | mask_interrupts | 
|  | 194 | #endif | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 195 | pushm	r12		/* r12_orig */ | 
|  | 196 | stmts	--sp, r0-lr | 
| Philippe Rétornaz | a7e30b8 | 2007-10-10 18:52:24 -0400 | [diff] [blame] | 197 |  | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 198 | mfsr	r0, SYSREG_RAR_SUP | 
|  | 199 | mfsr	r1, SYSREG_RSR_SUP | 
| Philippe Rétornaz | a7e30b8 | 2007-10-10 18:52:24 -0400 | [diff] [blame] | 200 | #ifdef CONFIG_PREEMPT | 
|  | 201 | unmask_interrupts | 
|  | 202 | #endif | 
|  | 203 | zero_fp | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 204 | stm	--sp, r0-r1 | 
|  | 205 |  | 
|  | 206 | /* check for syscall tracing */ | 
|  | 207 | get_thread_info r0 | 
|  | 208 | ld.w	r1, r0[TI_flags] | 
|  | 209 | bld	r1, TIF_SYSCALL_TRACE | 
|  | 210 | brcs	syscall_trace_enter | 
|  | 211 |  | 
|  | 212 | syscall_trace_cont: | 
|  | 213 | cp.w	r8, NR_syscalls | 
|  | 214 | brhs	syscall_badsys | 
|  | 215 |  | 
|  | 216 | lddpc   lr, syscall_table_addr | 
|  | 217 | ld.w    lr, lr[r8 << 2] | 
|  | 218 | mov	r8, r5		/* 5th argument (6th is pushed by stub) */ | 
|  | 219 | icall   lr | 
|  | 220 |  | 
|  | 221 | .global	syscall_return | 
|  | 222 | syscall_return: | 
|  | 223 | get_thread_info r0 | 
|  | 224 | mask_interrupts		/* make sure we don't miss an interrupt | 
|  | 225 | setting need_resched or sigpending | 
|  | 226 | between sampling and the rets */ | 
|  | 227 |  | 
|  | 228 | /* Store the return value so that the correct value is loaded below */ | 
|  | 229 | stdsp   sp[REG_R12], r12 | 
|  | 230 |  | 
|  | 231 | ld.w	r1, r0[TI_flags] | 
|  | 232 | andl	r1, _TIF_ALLWORK_MASK, COH | 
|  | 233 | brne	syscall_exit_work | 
|  | 234 |  | 
|  | 235 | syscall_exit_cont: | 
|  | 236 | popm	r8-r9 | 
|  | 237 | mtsr	SYSREG_RAR_SUP, r8 | 
|  | 238 | mtsr	SYSREG_RSR_SUP, r9 | 
|  | 239 | ldmts	sp++, r0-lr | 
|  | 240 | sub	sp, -4		/* r12_orig */ | 
|  | 241 | rets | 
|  | 242 |  | 
|  | 243 | .align	2 | 
|  | 244 | syscall_table_addr: | 
|  | 245 | .long   sys_call_table | 
|  | 246 |  | 
|  | 247 | syscall_badsys: | 
|  | 248 | mov	r12, -ENOSYS | 
|  | 249 | rjmp	syscall_return | 
|  | 250 |  | 
|  | 251 | .global ret_from_fork | 
|  | 252 | ret_from_fork: | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 253 | call   schedule_tail | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 254 |  | 
|  | 255 | /* check for syscall tracing */ | 
|  | 256 | get_thread_info r0 | 
|  | 257 | ld.w	r1, r0[TI_flags] | 
|  | 258 | andl	r1, _TIF_ALLWORK_MASK, COH | 
|  | 259 | brne	syscall_exit_work | 
|  | 260 | rjmp    syscall_exit_cont | 
|  | 261 |  | 
|  | 262 | syscall_trace_enter: | 
|  | 263 | pushm	r8-r12 | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 264 | call	syscall_trace | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 265 | popm	r8-r12 | 
|  | 266 | rjmp	syscall_trace_cont | 
|  | 267 |  | 
|  | 268 | syscall_exit_work: | 
|  | 269 | bld	r1, TIF_SYSCALL_TRACE | 
|  | 270 | brcc	1f | 
|  | 271 | unmask_interrupts | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 272 | call	syscall_trace | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 273 | mask_interrupts | 
|  | 274 | ld.w	r1, r0[TI_flags] | 
|  | 275 |  | 
|  | 276 | 1:	bld	r1, TIF_NEED_RESCHED | 
|  | 277 | brcc	2f | 
|  | 278 | unmask_interrupts | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 279 | call	schedule | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 280 | mask_interrupts | 
|  | 281 | ld.w	r1, r0[TI_flags] | 
|  | 282 | rjmp	1b | 
|  | 283 |  | 
| David Howells | d0420c8 | 2009-09-02 09:14:16 +0100 | [diff] [blame] | 284 | 2:	mov	r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NOTIFY_RESUME | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 285 | tst	r1, r2 | 
|  | 286 | breq	3f | 
|  | 287 | unmask_interrupts | 
|  | 288 | mov	r12, sp | 
|  | 289 | mov	r11, r0 | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 290 | call	do_notify_resume | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 291 | mask_interrupts | 
|  | 292 | ld.w	r1, r0[TI_flags] | 
|  | 293 | rjmp	1b | 
|  | 294 |  | 
|  | 295 | 3:	bld	r1, TIF_BREAKPOINT | 
|  | 296 | brcc	syscall_exit_cont | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 297 | rjmp	enter_monitor_mode | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 298 |  | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 299 | /* This function expects to find offending PC in SYSREG_RAR_EX */ | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 300 | .type	save_full_context_ex, @function | 
|  | 301 | .align	2 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 302 | save_full_context_ex: | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 303 | mfsr	r11, SYSREG_RAR_EX | 
|  | 304 | sub	r9, pc, . - debug_trampoline | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 305 | mfsr	r8, SYSREG_RSR_EX | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 306 | cp.w	r9, r11 | 
|  | 307 | breq	3f | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 308 | mov	r12, r8 | 
|  | 309 | andh	r8, (MODE_MASK >> 16), COH | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 310 | brne	2f | 
|  | 311 |  | 
|  | 312 | 1:	pushm	r11, r12	/* PC and SR */ | 
|  | 313 | unmask_exceptions | 
|  | 314 | ret	r12 | 
|  | 315 |  | 
|  | 316 | 2:	sub	r10, sp, -(FRAME_SIZE_FULL - REG_LR) | 
|  | 317 | stdsp	sp[4], r10	/* replace saved SP */ | 
|  | 318 | rjmp	1b | 
|  | 319 |  | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 320 | /* | 
|  | 321 | * The debug handler set up a trampoline to make us | 
|  | 322 | * automatically enter monitor mode upon return, but since | 
|  | 323 | * we're saving the full context, we must assume that the | 
|  | 324 | * exception handler might want to alter the return address | 
|  | 325 | * and/or status register. So we need to restore the original | 
|  | 326 | * context and enter monitor mode manually after the exception | 
|  | 327 | * has been handled. | 
|  | 328 | */ | 
|  | 329 | 3:	get_thread_info r8 | 
|  | 330 | ld.w	r11, r8[TI_rar_saved] | 
|  | 331 | ld.w	r12, r8[TI_rsr_saved] | 
|  | 332 | rjmp	1b | 
|  | 333 | .size	save_full_context_ex, . - save_full_context_ex | 
|  | 334 |  | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 335 | /* Low-level exception handlers */ | 
|  | 336 | handle_critical: | 
| Haavard Skinnemoen | 9e3f544 | 2008-08-20 15:46:24 +0200 | [diff] [blame] | 337 | /* | 
|  | 338 | * AT32AP700x errata: | 
|  | 339 | * | 
|  | 340 | * After a Java stack overflow or underflow trap, any CPU | 
|  | 341 | * memory access may cause erratic behavior. This will happen | 
|  | 342 | * when the four least significant bits of the JOSP system | 
|  | 343 | * register contains any value between 9 and 15 (inclusive). | 
|  | 344 | * | 
|  | 345 | * Possible workarounds: | 
|  | 346 | *   - Don't use the Java Extension Module | 
|  | 347 | *   - Ensure that the stack overflow and underflow trap | 
|  | 348 | *     handlers do not do any memory access or trigger any | 
|  | 349 | *     exceptions before the overflow/underflow condition is | 
|  | 350 | *     cleared (by incrementing or decrementing the JOSP) | 
|  | 351 | *   - Make sure that JOSP does not contain any problematic | 
|  | 352 | *     value before doing any exception or interrupt | 
|  | 353 | *     processing. | 
|  | 354 | *   - Set up a critical exception handler which writes a | 
|  | 355 | *     known-to-be-safe value, e.g. 4, to JOSP before doing | 
|  | 356 | *     any further processing. | 
|  | 357 | * | 
|  | 358 | * We'll use the last workaround for now since we cannot | 
|  | 359 | * guarantee that user space processes don't use Java mode. | 
|  | 360 | * Non-well-behaving userland will be terminated with extreme | 
|  | 361 | * prejudice. | 
|  | 362 | */ | 
|  | 363 | #ifdef CONFIG_CPU_AT32AP700X | 
|  | 364 | /* | 
|  | 365 | * There's a chance we can't touch memory, so temporarily | 
|  | 366 | * borrow PTBR to save the stack pointer while we fix things | 
|  | 367 | * up... | 
|  | 368 | */ | 
|  | 369 | mtsr	SYSREG_PTBR, sp | 
|  | 370 | mov	sp, 4 | 
|  | 371 | mtsr	SYSREG_JOSP, sp | 
|  | 372 | mfsr	sp, SYSREG_PTBR | 
|  | 373 | sub	pc, -2 | 
|  | 374 |  | 
|  | 375 | /* Push most of pt_regs on stack. We'll do the rest later */ | 
| Haavard Skinnemoen | 5998a3c | 2007-12-03 18:30:15 +0100 | [diff] [blame] | 376 | sub	sp, 4 | 
| Haavard Skinnemoen | 9e3f544 | 2008-08-20 15:46:24 +0200 | [diff] [blame] | 377 | pushm	r0-r12 | 
|  | 378 |  | 
|  | 379 | /* PTBR mirrors current_thread_info()->task->active_mm->pgd */ | 
|  | 380 | get_thread_info r0 | 
|  | 381 | ld.w	r1, r0[TI_task] | 
|  | 382 | ld.w	r2, r1[TSK_active_mm] | 
|  | 383 | ld.w	r3, r2[MM_pgd] | 
|  | 384 | mtsr	SYSREG_PTBR, r3 | 
|  | 385 | #else | 
|  | 386 | sub	sp, 4 | 
|  | 387 | pushm	r0-r12 | 
|  | 388 | #endif | 
|  | 389 | sub	r0, sp, -(14 * 4) | 
|  | 390 | mov	r1, lr | 
|  | 391 | mfsr	r2, SYSREG_RAR_EX | 
|  | 392 | mfsr	r3, SYSREG_RSR_EX | 
|  | 393 | pushm	r0-r3 | 
|  | 394 |  | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 395 | mfsr	r12, SYSREG_ECR | 
|  | 396 | mov	r11, sp | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 397 | call	do_critical_exception | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 398 |  | 
|  | 399 | /* We should never get here... */ | 
|  | 400 | bad_return: | 
|  | 401 | sub	r12, pc, (. - 1f) | 
|  | 402 | bral	panic | 
|  | 403 | .align	2 | 
|  | 404 | 1:	.asciz	"Return from critical exception!" | 
|  | 405 |  | 
|  | 406 | .align	1 | 
|  | 407 | do_bus_error_write: | 
|  | 408 | sub	sp, 4 | 
|  | 409 | stmts	--sp, r0-lr | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 410 | call	save_full_context_ex | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 411 | mov	r11, 1 | 
|  | 412 | rjmp	1f | 
|  | 413 |  | 
|  | 414 | do_bus_error_read: | 
|  | 415 | sub	sp, 4 | 
|  | 416 | stmts	--sp, r0-lr | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 417 | call	save_full_context_ex | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 418 | mov	r11, 0 | 
|  | 419 | 1:	mfsr	r12, SYSREG_BEAR | 
|  | 420 | mov	r10, sp | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 421 | call	do_bus_error | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 422 | rjmp	ret_from_exception | 
|  | 423 |  | 
|  | 424 | .align	1 | 
|  | 425 | do_nmi_ll: | 
|  | 426 | sub	sp, 4 | 
|  | 427 | stmts	--sp, r0-lr | 
| Haavard Skinnemoen | 92b728c | 2007-03-13 10:06:37 +0100 | [diff] [blame] | 428 | mfsr	r9, SYSREG_RSR_NMI | 
|  | 429 | mfsr	r8, SYSREG_RAR_NMI | 
|  | 430 | bfextu	r0, r9, MODE_SHIFT, 3 | 
|  | 431 | brne	2f | 
|  | 432 |  | 
|  | 433 | 1:	pushm	r8, r9	/* PC and SR */ | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 434 | mfsr	r12, SYSREG_ECR | 
|  | 435 | mov	r11, sp | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 436 | call	do_nmi | 
| Haavard Skinnemoen | 92b728c | 2007-03-13 10:06:37 +0100 | [diff] [blame] | 437 | popm	r8-r9 | 
|  | 438 | mtsr	SYSREG_RAR_NMI, r8 | 
|  | 439 | tst	r0, r0 | 
|  | 440 | mtsr	SYSREG_RSR_NMI, r9 | 
|  | 441 | brne	3f | 
|  | 442 |  | 
|  | 443 | ldmts	sp++, r0-lr | 
|  | 444 | sub	sp, -4		/* skip r12_orig */ | 
|  | 445 | rete | 
|  | 446 |  | 
|  | 447 | 2:	sub	r10, sp, -(FRAME_SIZE_FULL - REG_LR) | 
|  | 448 | stdsp	sp[4], r10	/* replace saved SP */ | 
|  | 449 | rjmp	1b | 
|  | 450 |  | 
|  | 451 | 3:	popm	lr | 
|  | 452 | sub	sp, -4		/* skip sp */ | 
|  | 453 | popm	r0-r12 | 
|  | 454 | sub	sp, -4		/* skip r12_orig */ | 
|  | 455 | rete | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 456 |  | 
|  | 457 | handle_address_fault: | 
|  | 458 | sub	sp, 4 | 
|  | 459 | stmts	--sp, r0-lr | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 460 | call	save_full_context_ex | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 461 | mfsr	r12, SYSREG_ECR | 
|  | 462 | mov	r11, sp | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 463 | call	do_address_exception | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 464 | rjmp	ret_from_exception | 
|  | 465 |  | 
|  | 466 | handle_protection_fault: | 
|  | 467 | sub	sp, 4 | 
|  | 468 | stmts	--sp, r0-lr | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 469 | call	save_full_context_ex | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 470 | mfsr	r12, SYSREG_ECR | 
|  | 471 | mov	r11, sp | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 472 | call	do_page_fault | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 473 | rjmp	ret_from_exception | 
|  | 474 |  | 
|  | 475 | .align	1 | 
|  | 476 | do_illegal_opcode_ll: | 
|  | 477 | sub	sp, 4 | 
|  | 478 | stmts	--sp, r0-lr | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 479 | call	save_full_context_ex | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 480 | mfsr	r12, SYSREG_ECR | 
|  | 481 | mov	r11, sp | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 482 | call	do_illegal_opcode | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 483 | rjmp	ret_from_exception | 
|  | 484 |  | 
|  | 485 | do_dtlb_modified: | 
|  | 486 | pushm	r0-r3 | 
|  | 487 | mfsr	r1, SYSREG_TLBEAR | 
|  | 488 | mfsr	r0, SYSREG_PTBR | 
|  | 489 | lsr	r2, r1, PGDIR_SHIFT | 
|  | 490 | ld.w	r0, r0[r2 << 2] | 
|  | 491 | lsl	r1, (32 - PGDIR_SHIFT) | 
|  | 492 | lsr	r1, (32 - PGDIR_SHIFT) + PAGE_SHIFT | 
|  | 493 |  | 
|  | 494 | /* Translate to virtual address in P1 */ | 
|  | 495 | andl	r0, 0xf000 | 
|  | 496 | sbr	r0, 31 | 
|  | 497 | add	r2, r0, r1 << 2 | 
|  | 498 | ld.w	r3, r2[0] | 
|  | 499 | sbr	r3, _PAGE_BIT_DIRTY | 
|  | 500 | mov	r0, r3 | 
|  | 501 | st.w	r2[0], r3 | 
|  | 502 |  | 
|  | 503 | /* The page table is up-to-date. Update the TLB entry as well */ | 
|  | 504 | andl	r0, lo(_PAGE_FLAGS_HARDWARE_MASK) | 
|  | 505 | mtsr	SYSREG_TLBELO, r0 | 
|  | 506 |  | 
|  | 507 | /* MMUCR[DRP] is updated automatically, so let's go... */ | 
|  | 508 | tlbw | 
|  | 509 |  | 
|  | 510 | popm	r0-r3 | 
|  | 511 | rete | 
|  | 512 |  | 
|  | 513 | do_fpe_ll: | 
|  | 514 | sub	sp, 4 | 
|  | 515 | stmts	--sp, r0-lr | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 516 | call	save_full_context_ex | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 517 | unmask_interrupts | 
|  | 518 | mov	r12, 26 | 
|  | 519 | mov	r11, sp | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 520 | call	do_fpe | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 521 | rjmp	ret_from_exception | 
|  | 522 |  | 
|  | 523 | ret_from_exception: | 
|  | 524 | mask_interrupts | 
|  | 525 | lddsp	r4, sp[REG_SR] | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 526 |  | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 527 | andh	r4, (MODE_MASK >> 16), COH | 
|  | 528 | brne	fault_resume_kernel | 
|  | 529 |  | 
|  | 530 | get_thread_info r0 | 
|  | 531 | ld.w	r1, r0[TI_flags] | 
|  | 532 | andl	r1, _TIF_WORK_MASK, COH | 
|  | 533 | brne	fault_exit_work | 
|  | 534 |  | 
|  | 535 | fault_resume_user: | 
|  | 536 | popm	r8-r9 | 
|  | 537 | mask_exceptions | 
|  | 538 | mtsr	SYSREG_RAR_EX, r8 | 
|  | 539 | mtsr	SYSREG_RSR_EX, r9 | 
|  | 540 | ldmts	sp++, r0-lr | 
|  | 541 | sub	sp, -4 | 
|  | 542 | rete | 
|  | 543 |  | 
|  | 544 | fault_resume_kernel: | 
|  | 545 | #ifdef CONFIG_PREEMPT | 
|  | 546 | get_thread_info	r0 | 
|  | 547 | ld.w	r2, r0[TI_preempt_count] | 
|  | 548 | cp.w	r2, 0 | 
|  | 549 | brne	1f | 
|  | 550 | ld.w	r1, r0[TI_flags] | 
|  | 551 | bld	r1, TIF_NEED_RESCHED | 
|  | 552 | brcc	1f | 
|  | 553 | lddsp	r4, sp[REG_SR] | 
|  | 554 | bld	r4, SYSREG_GM_OFFSET | 
|  | 555 | brcs	1f | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 556 | call	preempt_schedule_irq | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 557 | 1: | 
|  | 558 | #endif | 
|  | 559 |  | 
|  | 560 | popm	r8-r9 | 
|  | 561 | mask_exceptions | 
|  | 562 | mfsr	r1, SYSREG_SR | 
|  | 563 | mtsr	SYSREG_RAR_EX, r8 | 
|  | 564 | mtsr	SYSREG_RSR_EX, r9 | 
|  | 565 | popm	lr | 
|  | 566 | sub	sp, -4		/* ignore SP */ | 
|  | 567 | popm	r0-r12 | 
|  | 568 | sub	sp, -4		/* ignore r12_orig */ | 
|  | 569 | rete | 
|  | 570 |  | 
|  | 571 | irq_exit_work: | 
|  | 572 | /* Switch to exception mode so that we can share the same code. */ | 
|  | 573 | mfsr	r8, SYSREG_SR | 
|  | 574 | cbr	r8, SYSREG_M0_OFFSET | 
|  | 575 | orh	r8, hi(SYSREG_BIT(M1) | SYSREG_BIT(M2)) | 
|  | 576 | mtsr	SYSREG_SR, r8 | 
|  | 577 | sub	pc, -2 | 
|  | 578 | get_thread_info r0 | 
|  | 579 | ld.w	r1, r0[TI_flags] | 
|  | 580 |  | 
|  | 581 | fault_exit_work: | 
|  | 582 | bld	r1, TIF_NEED_RESCHED | 
|  | 583 | brcc	1f | 
|  | 584 | unmask_interrupts | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 585 | call	schedule | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 586 | mask_interrupts | 
|  | 587 | ld.w	r1, r0[TI_flags] | 
|  | 588 | rjmp	fault_exit_work | 
|  | 589 |  | 
|  | 590 | 1:	mov	r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | 
|  | 591 | tst	r1, r2 | 
|  | 592 | breq	2f | 
|  | 593 | unmask_interrupts | 
|  | 594 | mov	r12, sp | 
|  | 595 | mov	r11, r0 | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 596 | call	do_notify_resume | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 597 | mask_interrupts | 
|  | 598 | ld.w	r1, r0[TI_flags] | 
|  | 599 | rjmp	fault_exit_work | 
|  | 600 |  | 
|  | 601 | 2:	bld	r1, TIF_BREAKPOINT | 
|  | 602 | brcc	fault_resume_user | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 603 | rjmp	enter_monitor_mode | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 604 |  | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 605 | .section .kprobes.text, "ax", @progbits | 
|  | 606 | .type	handle_debug, @function | 
|  | 607 | handle_debug: | 
|  | 608 | sub	sp, 4		/* r12_orig */ | 
|  | 609 | stmts	--sp, r0-lr | 
|  | 610 | mfsr	r8, SYSREG_RAR_DBG | 
|  | 611 | mfsr	r9, SYSREG_RSR_DBG | 
|  | 612 | unmask_exceptions | 
|  | 613 | pushm	r8-r9 | 
|  | 614 | bfextu	r9, r9, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE | 
|  | 615 | brne	debug_fixup_regs | 
|  | 616 |  | 
|  | 617 | .Ldebug_fixup_cont: | 
|  | 618 | #ifdef CONFIG_TRACE_IRQFLAGS | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 619 | call	trace_hardirqs_off | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 620 | #endif | 
|  | 621 | mov	r12, sp | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 622 | call	do_debug | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 623 | mov	sp, r12 | 
|  | 624 |  | 
|  | 625 | lddsp	r2, sp[REG_SR] | 
|  | 626 | bfextu	r3, r2, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE | 
|  | 627 | brne	debug_resume_kernel | 
|  | 628 |  | 
|  | 629 | get_thread_info r0 | 
|  | 630 | ld.w	r1, r0[TI_flags] | 
|  | 631 | mov	r2, _TIF_DBGWORK_MASK | 
|  | 632 | tst	r1, r2 | 
|  | 633 | brne	debug_exit_work | 
|  | 634 |  | 
|  | 635 | bld	r1, TIF_SINGLE_STEP | 
|  | 636 | brcc	1f | 
|  | 637 | mfdr	r4, OCD_DC | 
|  | 638 | sbr	r4, OCD_DC_SS_BIT | 
|  | 639 | mtdr	OCD_DC, r4 | 
|  | 640 |  | 
|  | 641 | 1:	popm	r10,r11 | 
|  | 642 | mask_exceptions | 
|  | 643 | mtsr	SYSREG_RSR_DBG, r11 | 
|  | 644 | mtsr	SYSREG_RAR_DBG, r10 | 
|  | 645 | #ifdef CONFIG_TRACE_IRQFLAGS | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 646 | call	trace_hardirqs_on | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 647 | 1: | 
|  | 648 | #endif | 
|  | 649 | ldmts	sp++, r0-lr | 
|  | 650 | sub	sp, -4 | 
|  | 651 | retd | 
|  | 652 | .size	handle_debug, . - handle_debug | 
|  | 653 |  | 
|  | 654 | /* Mode of the trapped context is in r9 */ | 
|  | 655 | .type	debug_fixup_regs, @function | 
|  | 656 | debug_fixup_regs: | 
|  | 657 | mfsr	r8, SYSREG_SR | 
|  | 658 | mov	r10, r8 | 
|  | 659 | bfins	r8, r9, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE | 
|  | 660 | mtsr	SYSREG_SR, r8 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 661 | sub	pc, -2 | 
|  | 662 | stdsp	sp[REG_LR], lr | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 663 | mtsr	SYSREG_SR, r10 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 664 | sub	pc, -2 | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 665 | sub	r8, sp, -FRAME_SIZE_FULL | 
|  | 666 | stdsp	sp[REG_SP], r8 | 
|  | 667 | rjmp	.Ldebug_fixup_cont | 
|  | 668 | .size	debug_fixup_regs, . - debug_fixup_regs | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 669 |  | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 670 | .type	debug_resume_kernel, @function | 
|  | 671 | debug_resume_kernel: | 
|  | 672 | mask_exceptions | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 673 | popm	r10, r11 | 
|  | 674 | mtsr	SYSREG_RAR_DBG, r10 | 
|  | 675 | mtsr	SYSREG_RSR_DBG, r11 | 
| Haavard Skinnemoen | 320516b | 2007-11-26 14:34:57 +0100 | [diff] [blame] | 676 | #ifdef CONFIG_TRACE_IRQFLAGS | 
|  | 677 | bld	r11, SYSREG_GM_OFFSET | 
|  | 678 | brcc	1f | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 679 | call	trace_hardirqs_on | 
| Haavard Skinnemoen | 320516b | 2007-11-26 14:34:57 +0100 | [diff] [blame] | 680 | 1: | 
|  | 681 | #endif | 
|  | 682 | mfsr	r2, SYSREG_SR | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 683 | mov	r1, r2 | 
|  | 684 | bfins	r2, r3, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE | 
| Haavard Skinnemoen | 320516b | 2007-11-26 14:34:57 +0100 | [diff] [blame] | 685 | mtsr	SYSREG_SR, r2 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 686 | sub	pc, -2 | 
|  | 687 | popm	lr | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 688 | mtsr	SYSREG_SR, r1 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 689 | sub	pc, -2 | 
|  | 690 | sub	sp, -4		/* skip SP */ | 
|  | 691 | popm	r0-r12 | 
|  | 692 | sub	sp, -4 | 
|  | 693 | retd | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 694 | .size	debug_resume_kernel, . - debug_resume_kernel | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 695 |  | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 696 | .type	debug_exit_work, @function | 
|  | 697 | debug_exit_work: | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 698 | /* | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 699 | * We must return from Monitor Mode using a retd, and we must | 
|  | 700 | * not schedule since that involves the D bit in SR getting | 
|  | 701 | * cleared by something other than the debug hardware. This | 
|  | 702 | * may cause undefined behaviour according to the Architecture | 
|  | 703 | * manual. | 
|  | 704 | * | 
|  | 705 | * So we fix up the return address and status and return to a | 
|  | 706 | * stub below in Exception mode. From there, we can follow the | 
|  | 707 | * normal exception return path. | 
|  | 708 | * | 
|  | 709 | * The real return address and status registers are stored on | 
|  | 710 | * the stack in the way the exception return path understands, | 
|  | 711 | * so no need to fix anything up there. | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 712 | */ | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 713 | sub	r8, pc, . - fault_exit_work | 
|  | 714 | mtsr	SYSREG_RAR_DBG, r8 | 
|  | 715 | mov	r9, 0 | 
|  | 716 | orh	r9, hi(SR_EM | SR_GM | MODE_EXCEPTION) | 
|  | 717 | mtsr	SYSREG_RSR_DBG, r9 | 
|  | 718 | sub	pc, -2 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 719 | retd | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 720 | .size	debug_exit_work, . - debug_exit_work | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 721 |  | 
|  | 722 | .set	rsr_int0,	SYSREG_RSR_INT0 | 
|  | 723 | .set	rsr_int1,	SYSREG_RSR_INT1 | 
|  | 724 | .set	rsr_int2,	SYSREG_RSR_INT2 | 
|  | 725 | .set	rsr_int3,	SYSREG_RSR_INT3 | 
|  | 726 | .set	rar_int0,	SYSREG_RAR_INT0 | 
|  | 727 | .set	rar_int1,	SYSREG_RAR_INT1 | 
|  | 728 | .set	rar_int2,	SYSREG_RAR_INT2 | 
|  | 729 | .set	rar_int3,	SYSREG_RAR_INT3 | 
|  | 730 |  | 
|  | 731 | .macro	IRQ_LEVEL level | 
|  | 732 | .type	irq_level\level, @function | 
|  | 733 | irq_level\level: | 
|  | 734 | sub	sp, 4		/* r12_orig */ | 
|  | 735 | stmts	--sp,r0-lr | 
|  | 736 | mfsr	r8, rar_int\level | 
|  | 737 | mfsr	r9, rsr_int\level | 
| Philippe Rétornaz | a7e30b8 | 2007-10-10 18:52:24 -0400 | [diff] [blame] | 738 |  | 
|  | 739 | #ifdef CONFIG_PREEMPT | 
|  | 740 | sub	r11, pc, (. - system_call) | 
|  | 741 | cp.w	r11, r8 | 
|  | 742 | breq	4f | 
|  | 743 | #endif | 
|  | 744 |  | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 745 | pushm	r8-r9 | 
|  | 746 |  | 
|  | 747 | mov	r11, sp | 
|  | 748 | mov	r12, \level | 
|  | 749 |  | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 750 | call	do_IRQ | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 751 |  | 
|  | 752 | lddsp	r4, sp[REG_SR] | 
| Hans-Christian Egtvedt | 19b7ce8 | 2007-02-26 13:50:43 +0100 | [diff] [blame] | 753 | bfextu	r4, r4, SYSREG_M0_OFFSET, 3 | 
|  | 754 | cp.w	r4, MODE_SUPERVISOR >> SYSREG_M0_OFFSET | 
|  | 755 | breq	2f | 
|  | 756 | cp.w	r4, MODE_USER >> SYSREG_M0_OFFSET | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 757 | #ifdef CONFIG_PREEMPT | 
| Hans-Christian Egtvedt | 19b7ce8 | 2007-02-26 13:50:43 +0100 | [diff] [blame] | 758 | brne	3f | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 759 | #else | 
|  | 760 | brne	1f | 
|  | 761 | #endif | 
|  | 762 |  | 
|  | 763 | get_thread_info	r0 | 
|  | 764 | ld.w	r1, r0[TI_flags] | 
|  | 765 | andl	r1, _TIF_WORK_MASK, COH | 
|  | 766 | brne	irq_exit_work | 
|  | 767 |  | 
| Haavard Skinnemoen | 320516b | 2007-11-26 14:34:57 +0100 | [diff] [blame] | 768 | 1: | 
|  | 769 | #ifdef CONFIG_TRACE_IRQFLAGS | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 770 | call	trace_hardirqs_on | 
| Haavard Skinnemoen | 320516b | 2007-11-26 14:34:57 +0100 | [diff] [blame] | 771 | #endif | 
|  | 772 | popm	r8-r9 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 773 | mtsr	rar_int\level, r8 | 
|  | 774 | mtsr	rsr_int\level, r9 | 
|  | 775 | ldmts	sp++,r0-lr | 
|  | 776 | sub	sp, -4		/* ignore r12_orig */ | 
|  | 777 | rete | 
|  | 778 |  | 
| Philippe Rétornaz | a7e30b8 | 2007-10-10 18:52:24 -0400 | [diff] [blame] | 779 | #ifdef CONFIG_PREEMPT | 
|  | 780 | 4:	mask_interrupts | 
|  | 781 | mfsr	r8, rsr_int\level | 
|  | 782 | sbr	r8, 16 | 
|  | 783 | mtsr	rsr_int\level, r8 | 
|  | 784 | ldmts	sp++, r0-lr | 
|  | 785 | sub	sp, -4		/* ignore r12_orig */ | 
|  | 786 | rete | 
|  | 787 | #endif | 
|  | 788 |  | 
| Hans-Christian Egtvedt | 19b7ce8 | 2007-02-26 13:50:43 +0100 | [diff] [blame] | 789 | 2:	get_thread_info	r0 | 
|  | 790 | ld.w	r1, r0[TI_flags] | 
|  | 791 | bld	r1, TIF_CPU_GOING_TO_SLEEP | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 792 | #ifdef CONFIG_PREEMPT | 
| Hans-Christian Egtvedt | 19b7ce8 | 2007-02-26 13:50:43 +0100 | [diff] [blame] | 793 | brcc	3f | 
|  | 794 | #else | 
|  | 795 | brcc	1b | 
|  | 796 | #endif | 
|  | 797 | sub	r1, pc, . - cpu_idle_skip_sleep | 
|  | 798 | stdsp	sp[REG_PC], r1 | 
|  | 799 | #ifdef CONFIG_PREEMPT | 
|  | 800 | 3:	get_thread_info r0 | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 801 | ld.w	r2, r0[TI_preempt_count] | 
|  | 802 | cp.w	r2, 0 | 
|  | 803 | brne	1b | 
|  | 804 | ld.w	r1, r0[TI_flags] | 
|  | 805 | bld	r1, TIF_NEED_RESCHED | 
|  | 806 | brcc	1b | 
|  | 807 | lddsp	r4, sp[REG_SR] | 
|  | 808 | bld	r4, SYSREG_GM_OFFSET | 
|  | 809 | brcs	1b | 
| Ben Nizette | 8d29b7b | 2009-01-14 09:32:19 +1100 | [diff] [blame] | 810 | call	preempt_schedule_irq | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 811 | #endif | 
| Hans-Christian Egtvedt | 19b7ce8 | 2007-02-26 13:50:43 +0100 | [diff] [blame] | 812 | rjmp	1b | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 813 | .endm | 
|  | 814 |  | 
|  | 815 | .section .irq.text,"ax",@progbits | 
|  | 816 |  | 
| Haavard Skinnemoen | 5f97f7f | 2006-09-25 23:32:13 -0700 | [diff] [blame] | 817 | .global	irq_level0 | 
|  | 818 | .global	irq_level1 | 
|  | 819 | .global	irq_level2 | 
|  | 820 | .global	irq_level3 | 
|  | 821 | IRQ_LEVEL 0 | 
|  | 822 | IRQ_LEVEL 1 | 
|  | 823 | IRQ_LEVEL 2 | 
|  | 824 | IRQ_LEVEL 3 | 
| Haavard Skinnemoen | 2507bc1 | 2007-11-28 15:04:01 +0100 | [diff] [blame] | 825 |  | 
|  | 826 | .section .kprobes.text, "ax", @progbits | 
|  | 827 | .type	enter_monitor_mode, @function | 
|  | 828 | enter_monitor_mode: | 
|  | 829 | /* | 
|  | 830 | * We need to enter monitor mode to do a single step. The | 
|  | 831 | * monitor code will alter the return address so that we | 
|  | 832 | * return directly to the user instead of returning here. | 
|  | 833 | */ | 
|  | 834 | breakpoint | 
|  | 835 | rjmp	breakpoint_failed | 
|  | 836 |  | 
|  | 837 | .size	enter_monitor_mode, . - enter_monitor_mode | 
|  | 838 |  | 
|  | 839 | .type	debug_trampoline, @function | 
|  | 840 | .global	debug_trampoline | 
|  | 841 | debug_trampoline: | 
|  | 842 | /* | 
|  | 843 | * Save the registers on the stack so that the monitor code | 
|  | 844 | * can find them easily. | 
|  | 845 | */ | 
|  | 846 | sub	sp, 4		/* r12_orig */ | 
|  | 847 | stmts	--sp, r0-lr | 
|  | 848 | get_thread_info	r0 | 
|  | 849 | ld.w	r8, r0[TI_rar_saved] | 
|  | 850 | ld.w	r9, r0[TI_rsr_saved] | 
|  | 851 | pushm	r8-r9 | 
|  | 852 |  | 
|  | 853 | /* | 
|  | 854 | * The monitor code will alter the return address so we don't | 
|  | 855 | * return here. | 
|  | 856 | */ | 
|  | 857 | breakpoint | 
|  | 858 | rjmp	breakpoint_failed | 
|  | 859 | .size	debug_trampoline, . - debug_trampoline | 
|  | 860 |  | 
|  | 861 | .type breakpoint_failed, @function | 
|  | 862 | breakpoint_failed: | 
|  | 863 | /* | 
|  | 864 | * Something went wrong. Perhaps the debug hardware isn't | 
|  | 865 | * enabled? | 
|  | 866 | */ | 
|  | 867 | lda.w	r12, msg_breakpoint_failed | 
|  | 868 | mov	r11, sp | 
|  | 869 | mov	r10, 9		/* SIGKILL */ | 
|  | 870 | call	die | 
|  | 871 | 1:	rjmp	1b | 
|  | 872 |  | 
|  | 873 | msg_breakpoint_failed: | 
|  | 874 | .asciz	"Failed to enter Debug Mode" |