entry.S 10.5 KB
Newer Older
1
/*
2
 * arch/sh/kernel/cpu/sh3/entry.S
L
Linus Torvalds 已提交
3 4
 *
 *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
5
 *  Copyright (C) 2003 - 2006  Paul Mundt
L
Linus Torvalds 已提交
6 7 8 9 10 11
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 */
#include <linux/sys.h>
P
Paul Mundt 已提交
12
#include <linux/errno.h>
L
Linus Torvalds 已提交
13 14 15
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
16
#include <asm/unistd.h>
P
Paul Mundt 已提交
17
#include <cpu/mmu_context.h>
18
#include <asm/page.h>
19
#include <asm/cache.h>
L
Linus Torvalds 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

! NOTE:
! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
! to be jumped is too far, but it causes illegal slot exception.

/*	
 * entry.S contains the system-call and fault low-level handling routines.
 * This also contains the timer-interrupt handler, as well as all interrupts
 * and faults that can result in a task-switch.
 *
 * NOTE: This code handles signal-recognition, which happens every time
 * after a timer-interrupt and after each system call.
 *
 * NOTE: This code uses a convention that instructions in the delay slot
 * of a transfer-control instruction are indented by an extra space, thus:
 *
 *    jmp	@k0	    ! control-transfer instruction
 *     ldc	k1, ssr     ! delay slot
 *
 * Stack layout in 'ret_from_syscall':
 * 	ptrace needs to have all regs on the stack.
 *	if the order here is changed, it needs to be
 *	updated in ptrace.c and ptrace.h
 *
 *	r0
 *      ...
 *	r15 = stack pointer
 *	spc
 *	pr
 *	ssr
 *	gbr
 *	mach
 *	macl
 *	syscall #
 *
 */
/* Offsets to the stack */
OFF_R0  =  0		/* Return value. New ABI also arg4 */
OFF_R1  =  4     	/* New ABI: arg5 */
OFF_R2  =  8     	/* New ABI: arg6 */
OFF_R3  =  12     	/* New ABI: syscall_nr */
OFF_R4  =  16     	/* New ABI: arg0 */
OFF_R5  =  20     	/* New ABI: arg1 */
OFF_R6  =  24     	/* New ABI: arg2 */
OFF_R7  =  28     	/* New ABI: arg3 */
OFF_SP	=  (15*4)
OFF_PC  =  (16*4)
OFF_SR	=  (16*4+8)
OFF_TRA	=  (16*4+6*4)

#define k0	r0
#define k1	r1
#define k2	r2
#define k3	r3
#define k4	r4

#define g_imask		r6	/* r6_bank1 */
#define k_g_imask	r6_bank	/* r6_bank1 */
#define current		r7	/* r7_bank1 */

80 81
#include <asm/entry-macros.S>
	
L
Linus Torvalds 已提交
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
/*
 * Kernel mode register usage:
 *	k0	scratch
 *	k1	scratch
 *	k2	scratch (Exception code)
 *	k3	scratch (Return address)
 *	k4	scratch
 *	k5	reserved
 *	k6	Global Interrupt Mask (0--15 << 4)
 *	k7	CURRENT_THREAD_INFO (pointer to current thread info)
 */

!
! TLB Miss / Initial Page write exception handling
!			_and_
! TLB hits, but the access violate the protection.
! It can be valid access, such as stack grow and/or C-O-W.
!
!
! Find the pmd/pte entry and loadtlb
! If it's not found, cause address error (SEGV)
!
! Although this could be written in assembly language (and it'd be faster),
! this first version depends *much* on C implementation.
!

#if defined(CONFIG_MMU)
	.align	2
ENTRY(tlb_miss_load)
111
	bra	call_handle_tlbmiss
L
Linus Torvalds 已提交
112 113 114 115
	 mov	#0, r5

	.align	2
ENTRY(tlb_miss_store)
116
	bra	call_handle_tlbmiss
L
Linus Torvalds 已提交
117 118 119 120
	 mov	#1, r5

	.align	2
ENTRY(initial_page_write)
121
	bra	call_handle_tlbmiss
122
	 mov	#2, r5
L
Linus Torvalds 已提交
123 124 125

	.align	2
ENTRY(tlb_protection_violation_load)
126
	bra	call_do_page_fault
L
Linus Torvalds 已提交
127 128 129 130
	 mov	#0, r5

	.align	2
ENTRY(tlb_protection_violation_store)
131
	bra	call_do_page_fault
L
Linus Torvalds 已提交
132 133
	 mov	#1, r5

134
call_handle_tlbmiss:
L
Linus Torvalds 已提交
135
	mov.l	1f, r0
136 137 138 139 140 141 142 143 144 145 146 147
	mov	r5, r8
	mov.l	@r0, r6
	mov.l	2f, r0
	sts	pr, r10
	jsr	@r0
	 mov	r15, r4
	!
	tst	r0, r0
	bf/s	0f
	 lds	r10, pr
	rts
	 nop
148
0:
149
	mov	r8, r5
150 151 152 153 154 155 156
call_do_page_fault:
	mov.l	1f, r0
	mov.l	@r0, r6

	mov.l	3f, r0
	mov.l	4f, r1
	mov	r15, r4
L
Linus Torvalds 已提交
157
	jmp	@r0
158
	 lds	r1, pr
L
Linus Torvalds 已提交
159 160 161

	.align 2
1:	.long	MMU_TEA
162
2:	.long	handle_tlbmiss
L
Linus Torvalds 已提交
163
3:	.long	do_page_fault
164
4:	.long	ret_from_exception
L
Linus Torvalds 已提交
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190

	.align	2
ENTRY(address_error_load)
	bra	call_dae
	 mov	#0,r5		! writeaccess = 0

	.align	2
ENTRY(address_error_store)
	bra	call_dae
	 mov	#1,r5		! writeaccess = 1

	.align	2
call_dae:
	mov.l	1f, r0
	mov.l	@r0, r6		! address
	mov.l	2f, r0
	jmp	@r0
	 mov	r15, r4		! regs

	.align 2
1:	.long	MMU_TEA
2:	.long   do_address_error
#endif /* CONFIG_MMU */

#if defined(CONFIG_SH_STANDARD_BIOS)
	/* Unwind the stack and jmp to the debug entry */
191
ENTRY(sh_bios_handler)
192 193 194 195 196 197
	mov.l	1f, r8
	bsr	restore_regs
	 nop

	lds	k2, pr			! restore pr
	mov	k4, r15
L
Linus Torvalds 已提交
198 199 200 201
	!
	mov.l	2f, k0
	mov.l	@k0, k0
	jmp	@k0
202
	 ldc	k3, ssr
L
Linus Torvalds 已提交
203 204 205 206 207
	.align	2
1:	.long	0x300000f0
2:	.long	gdb_vbr_vector
#endif /* CONFIG_SH_STANDARD_BIOS */

208 209 210 211 212 213 214 215 216 217 218 219
! restore_regs()
! - restore r0, r1, r2, r3, r4, r5, r6, r7 from the stack
! - switch bank
! - restore r8, r9, r10, r11, r12, r13, r14, r15 from the stack
! - restore spc, pr*, ssr, gbr, mach, macl, skip default tra
! k2 returns original pr
! k3 returns original sr
! k4 returns original stack pointer
! r8 passes SR bitmask, overwritten with restored data on return
! r9 trashed
! BL=0 on entry, on exit BL=1 (depending on r8).

M
Magnus Damm 已提交
220
ENTRY(restore_regs)
L
Linus Torvalds 已提交
221 222 223 224 225 226 227 228 229
	mov.l	@r15+, r0
	mov.l	@r15+, r1
	mov.l	@r15+, r2
	mov.l	@r15+, r3
	mov.l	@r15+, r4
	mov.l	@r15+, r5
	mov.l	@r15+, r6
	mov.l	@r15+, r7
	!
230 231 232
	stc	sr, r9
	or	r8, r9
	ldc	r9, sr
L
Linus Torvalds 已提交
233 234 235 236 237 238 239 240 241 242
	!
	mov.l	@r15+, r8
	mov.l	@r15+, r9
	mov.l	@r15+, r10
	mov.l	@r15+, r11
	mov.l	@r15+, r12
	mov.l	@r15+, r13
	mov.l	@r15+, r14
	mov.l	@r15+, k4		! original stack pointer
	ldc.l	@r15+, spc
243
	mov.l	@r15+, k2		! original PR
L
Linus Torvalds 已提交
244 245 246 247
	mov.l	@r15+, k3		! original SR
	ldc.l	@r15+, gbr
	lds.l	@r15+, mach
	lds.l	@r15+, macl
248 249 250 251 252 253 254 255 256
	rts
	 add	#4, r15			! Skip syscall number

restore_all:
	mov.l	7f, r8
	bsr	restore_regs
	 nop

	lds	k2, pr			! restore pr
L
Linus Torvalds 已提交
257 258 259
	!
	! Calculate new SR value
	mov	k3, k2			! original SR value
260
	mov	#0xfffffff0, k1
261 262
	extu.b	k1, k1
	not	k1, k1
263
	and	k1, k2			! Mask original SR value
L
Linus Torvalds 已提交
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
	!
	mov	k3, k0			! Calculate IMASK-bits
	shlr2	k0
	and	#0x3c, k0
	cmp/eq	#0x3c, k0
	bt/s	6f
	 shll2	k0
	mov	g_imask, k0
	!
6:	or	k0, k2			! Set the IMASK-bits
	ldc	k2, ssr
	!
	mov	k4, r15
	rte
	 nop

	.align	2
5:	.long	0x00001000	! DSP
7:	.long	0x30000000

284
! common exception handler
285
#include "../../entry-common.S"
286
	
L
Linus Torvalds 已提交
287 288 289 290 291 292 293
! Exception Vector Base
!
!	Should be aligned page boundary.
!
	.balign 	4096,0,4096
ENTRY(vbr_base)
	.long	0
294 295
!
! 0x100: General exception vector
L
Linus Torvalds 已提交
296 297 298
!
	.balign 	256,0,256
general_exception:
299 300
	bra	handle_exception
	 sts	pr, k3		! save original pr value in k3
L
Linus Torvalds 已提交
301

302
! prepare_stack()
303 304 305 306 307
! - roll back gRB
! - switch to kernel stack
! k0 returns original sp (after roll back)
! k1 trashed
! k2 trashed
308

309
prepare_stack:
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
#ifdef CONFIG_GUSA
	! Check for roll back gRB (User and Kernel)
	mov	r15, k0
	shll	k0
	bf/s	1f
	 shll	k0
	bf/s	1f
	 stc	spc, k1
	stc	r0_bank, k0
	cmp/hs	k0, k1		! test k1 (saved PC) >= k0 (saved r0)
	bt/s	2f
	 stc	r1_bank, k1

	add	#-2, k0
	add	r15, k0
	ldc	k0, spc		! PC = saved r0 + r15 - 2
2:	mov	k1, r15		! SP = r1
1:
#endif
329
	! Switch to kernel stack if needed
L
Linus Torvalds 已提交
330 331 332 333 334 335
	stc	ssr, k0		! Is it from kernel space?
	shll	k0		! Check MD bit (bit30) by shifting it into...
	shll	k0		!       ...the T bit
	bt/s	1f		! It's a kernel to kernel transition.
	 mov	r15, k0		! save original stack to k0
	/* User space to kernel */
336
	mov	#(THREAD_SIZE >> 10), k1
P
Paul Mundt 已提交
337
	shll8	k1		! k1 := THREAD_SIZE
338
	shll2	k1
L
Linus Torvalds 已提交
339 340 341
	add	current, k1
	mov	k1, r15		! change to kernel stack
	!
342 343 344
1:
	rts
	 nop
345

346 347 348 349 350 351
!
! 0x400: Instruction and Data TLB miss exception vector
!
	.balign 	1024,0,1024
tlb_miss:
	sts	pr, k3		! save original pr value in k3
352

353
handle_exception:
354 355
	mova	exception_data, k0

356
	! Setup stack and save DSP context (k0 contains original r15 on return)
357
	bsr	prepare_stack
358
	 PREF(k0)
359 360 361

	! Save registers / Switch to bank 0
	mov.l	5f, k2		! vector register address
M
Magnus Damm 已提交
362
	mov.l	1f, k4		! SR bits to clear in k4
363 364 365 366
	bsr	save_regs	! needs original pr value in k3
	 mov.l	@k2, k2		! read out vector and keep in k2

handle_exception_special:
367 368
	setup_frame_reg

369 370 371 372 373 374 375 376 377 378 379 380 381
	! Setup return address and jump to exception handler
	mov.l	7f, r9		! fetch return address
	stc	r2_bank, r0	! k2 (vector)
	mov.l	6f, r10
	shlr2	r0
	shlr	r0
	mov.l	@(r0, r10), r10
	jmp	@r10
	 lds	r9, pr		! put return address in pr

	.align	L1_CACHE_SHIFT

! save_regs()
382
! - save default tra, macl, mach, gbr, ssr, pr* and spc on the stack
383 384 385 386 387 388
! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack
! - switch bank
! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
! k0 contains original stack pointer*
! k1 trashed
! k3 passes original pr*
M
Magnus Damm 已提交
389
! k4 passes SR bitmask
390 391
! BL=1 on entry, on exit BL=0.

M
Magnus Damm 已提交
392
ENTRY(save_regs)
393 394
	mov	#-1, r1
	mov.l	k1, @-r15	! set TRA (default: -1)
L
Linus Torvalds 已提交
395 396 397 398
	sts.l	macl, @-r15
	sts.l	mach, @-r15
	stc.l	gbr, @-r15
	stc.l	ssr, @-r15
399
	mov.l	k3, @-r15	! original pr in k3
L
Linus Torvalds 已提交
400
	stc.l	spc, @-r15
401 402

	mov.l	k0, @-r15	! original stack pointer in k0
L
Linus Torvalds 已提交
403 404 405 406 407 408 409
	mov.l	r14, @-r15
	mov.l	r13, @-r15
	mov.l	r12, @-r15
	mov.l	r11, @-r15
	mov.l	r10, @-r15
	mov.l	r9, @-r15
	mov.l	r8, @-r15
410 411 412

	mov.l	0f, k3		! SR bits to set in k3

M
Magnus Damm 已提交
413 414 415 416 417 418 419 420 421
	! fall-through

! save_low_regs()
! - modify SR for bank switch
! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
! k3 passes bits to set in SR
! k4 passes bits to clear in SR

ENTRY(save_low_regs)
422 423 424 425 426
	stc	sr, r8
	or	k3, r8
	and	k4, r8
	ldc	r8, sr

L
Linus Torvalds 已提交
427 428 429 430 431 432 433
	mov.l	r7, @-r15
	mov.l	r6, @-r15
	mov.l	r5, @-r15
	mov.l	r4, @-r15
	mov.l	r3, @-r15
	mov.l	r2, @-r15
	mov.l	r1, @-r15
434
	rts
435
	 mov.l	r0, @-r15
L
Linus Torvalds 已提交
436

437 438 439 440 441 442
!
! 0x600: Interrupt / NMI vector
!
	.balign 	512,0,512
ENTRY(handle_interrupt)
	sts	pr, k3		! save original pr value in k3
443
	mova	exception_data, k0
L
Linus Torvalds 已提交
444

445
	! Setup stack and save DSP context (k0 contains original r15 on return)
446
	bsr	prepare_stack
447
	 PREF(k0)
448

449
	! Save registers / Switch to bank 0
M
Magnus Damm 已提交
450
	mov.l	1f, k4		! SR bits to clear in k4
451 452 453
	bsr	save_regs	! needs original pr value in k3
	 mov	#-1, k2		! default vector kept in k2

454 455
	setup_frame_reg

456 457 458 459 460 461 462 463
	stc	sr, r0	! get status register
	shlr2	r0
	and	#0x3c, r0
	cmp/eq	#0x3c, r0
	bf	9f
	TRACE_IRQS_OFF
9:

464 465 466 467 468 469
	! Setup return address and jump to do_IRQ
	mov.l	4f, r9		! fetch return address
	lds	r9, pr		! put return address in pr
	mov.l	2f, r4
	mov.l	3f, r9
	mov.l	@r4, r4		! pass INTEVT vector as arg0
P
Paul Mundt 已提交
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491

	shlr2	r4
	shlr	r4
	mov	r4, r0		! save vector->jmp table offset for later

	shlr2	r4		! vector to IRQ# conversion
	add	#-0x10, r4

	cmp/pz	r4		! is it a valid IRQ?
	bt	10f

	/*
	 * We got here as a result of taking the INTEVT path for something
	 * that isn't a valid hard IRQ, therefore we bypass the do_IRQ()
	 * path and special case the event dispatch instead.  This is the
	 * expected path for the NMI (and any other brilliantly implemented
	 * exception), which effectively wants regular exception dispatch
	 * but is unfortunately reported through INTEVT rather than
	 * EXPEVT.  Grr.
	 */
	mov.l	6f, r9
	mov.l	@(r0, r9), r9
492
	jmp	@r9
P
Paul Mundt 已提交
493 494 495 496
	 mov	r15, r8		! trap handlers take saved regs in r8

10:
	jmp	@r9		! Off to do_IRQ() we go.
497
	 mov	r15, r5		! pass saved registers as arg1
498

L
Linus Torvalds 已提交
499 500 501
ENTRY(exception_none)
	rts
	 nop
502 503 504 505 506 507 508 509 510 511 512

	.align	L1_CACHE_SHIFT
exception_data:
0:	.long	0x000080f0	! FD=1, IMASK=15
1:	.long	0xcfffffff	! RB=0, BL=0
2:	.long	INTEVT
3:	.long	do_IRQ
4:	.long	ret_from_irq
5:	.long	EXPEVT
6:	.long	exception_handling_table
7:	.long	ret_from_exception